Introduction
React.js is one of the most widely used libraries for building user interfaces today. At first glance, React.js can seem complex, and many developers may find it challenging to get started. This article aims to introduce beginners to some key features of React.js that might initially appear complicated.
- Variable changes will not reflect as you expect
- Async update
- If the statement is not allowed in the render
- Difference between () and {}
Let's dive deeper into each of these features.
1. Variable changes will not reflect as you expect
One of the first oddities you'll notice in React.js is that variable changes may not update as expected. For example,
import "./styles.css";
export default function App() {
let count = 1;
const IncreaseCount = () => {
count = count + 1;
};
return (
<div className="App">
<h2>Count: {count}</h2>
<button onClick={IncreaseCount}>Increase</button>
</div>
);
}
In this example, we are only increasing the count variable when the user clicks on the Increase button. As developers, we think this is a normal thing that should happen. Here's a live demo of this example.
As you may notice, the count variable's value does not increase when a button is clicked. To understand why, we need to delve into the concept of the DOM.
DOM
The DOM stands for Document Object Model. When we create an HTML page, it contains various tags like <body>, <p>, <div>, etc. These tags are structured into a tree-like format known as the DOM tree. For instance, consider the following HTML page:
<html>
<body>
<div>
<p>Hello</p>
</div>
<div>
<p>welcome</p>
</div>
</body>
</html>
In this scenario, the DOM will create a tree of elements (tags) as depicted below.
If we change the content of the p tag from Hello to Hello world, the entire tree of an element is re-created. In a large application, this can cost a lot because we will have many tags. On every change, the entire DOM will be re-created. To solve this problem, react virtual DOM came into the picture.
Virtual DOM
When the first time a page is created, the virtual DOM will create a copy of the real DOM. If we make any change in state or props, another copy of the virtual DOM will be created.
So except for the first time, we will have two copies of the virtual DOM,
- Updated virtual DOM
- Previous virtual DOM
React will use a different algorithm to identify a change in the DOM object (element or tag). The only changed object is updated on the real DOM.
With the help of virtual DOM, we are getting rid of re-creating the entire DOM on every state or props change. You might think that we will have an extra cost of creating a virtual DOM but the virtual DOM uses Javascript, which is lightweight and very fast.
React needs some indication on when it's supposed to re-create and compare DOM with old DOM (also known as re-render). React will re-render the component when the state or props of the component is updated. In our example, we are updating variable values which is not state or props.
The following counter program will work as expected as we will use the react state.
import { useState } from "react";
import "./styles.css";
export default function App() {
const [count, setCouner] = useState(1);
const IncreaseCount = () => {
setCouner((countValue) => countValue + 1);
console.log(count, "count");
};
return (
<div className="App">
<h2>Count: {count}</h2>
<button onClick={IncreaseCount}>Increase</button>
</div>
);
}
https://codesandbox.io/s/dry-field-w098l?file=/src/App.js
2. Async update
The second annoying thing is that console.log will not work as expected. Open a console and observe the results.
https://codesandbox.io/s/dry-field-w098l?file=/src/App.js
As you marked, the console is printing the previous value. Now let's understand why this happens.
As I explained, react depends on state and props for re-render. In real applications, different activities might be updating 10 different states at the same time. Now if react will recreate and compare DOM 10 times it will slow down the application. To solve this issue react update state asynchronously. So when 10 different states are updated react will create a bunch of 10 changes and update DOM only once. Here 10 state changes are for example. These 10 changes might not happen at the same time but might happen at fractionally different times. The point is that react.js will change state in a bunch to reduce the number of re-renders.
3. If the statement is not allowed in the render method
When I started working in react.js it was very weird for me that if statement is not allowed in the render method. In normal programming, we use it a lot. For example following code will not work.
export default function App() {
const data=1;
return (
if(data===1){
<h1>Hello form if block</h1>
}else{
<h1>Hello form else block</h1>
}
);
}
If you want conditional rendering in react.js you'll need to depend on the ternary operator. So you'll need to change code as,
export default function App() {
const data=1;
return (
data===1?<h1>Hello form if block</h1>
:<h1>Hello form else block</h1>
);
}
4. Difference between () and {}
When you start working in react.js you'll not understand why the following code is not working.
import "./styles.css";
export default function App() {
const data = 1;
return (
<>
<h1>Hello</h1>
{data === 1 ? <h1>data is 1</h1> : <h1>data is not 1</h1>}
</>
);
}
https://codesandbox.io/s/goofy-cartwright-ly20w?file=/src/App.js:0-185
If you'll visit the sandbox link you'll notice that.
(data===1?<h1>data is 1</h1>:<h1>data is not 1</h1>)
this line is returned as any HTML statement and ternary operation is not performed. In react.js we use () to return Html. In this example, we are trying to return HTML from HTML as we are using () twice. Correct code using {}.
import "./styles.css";
export default function App() {
const data = 1;
return (
<>
<h1>Hello</h1>
{data === 1 ? <h1>data is 1</h1> : <h1>data is not 1</h1>}
</>
);
}
In map difference of {} and ()
Consider the following map statement.
const allData = datas.map((data) => (
<Data key={data.id} name={Data.firstName+" "+Data.lastName} />
));
const allData = datas.map((data) => {
const name=data.firstName+" "+data.lastName
return <Data key={data.id} name={name} />
});
Both map statements are calling the Data component, but they do so in slightly different ways.
In the first example, we use () which directly returns the Data component. In the second example, we use {}, which allows us to perform additional operations before returning the Data component.
If you have any questions, feel free to ask in the comment section. Thank you!