Let's dive into React hooks. One thing to keep in mind is that hooks were introduced for functional components only. Hooks don't work inside classes.
Hooks are just functions responsible for certain behavior. In this article, we will be discussing useState and useEffect.
- useState
useState is a React hook used for managing state variables. We can declare a state variable and update it directly. useState is imported from the react module.
Here is an example of useState:
const [count,setCount] = useState(0)
Here, count
is the name of the variable, and setCount
is the name of the callback function that will update the state. useState(0)
means we set 0 as the default value. 0 will be rendered initially, and after that, when we update the variable, the new value will be rendered.
Now let's take an example of a counter app to learn more
import { useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
const increase = () => {
setCount(count + 1);
};
const decrease = () => {
setCount(count - 1);
};
return (
<div>
<h1>count : {count}</h1>
<button onClick={decrease}>-</button>
<button onClick={increase}>+</button>
</div>
);
}
In the above code, we use setCount
to update a new value, i.e., increasing the count by 1. Similarly, we can decrease the count value by 1. This is a basic way of writing code.
The problem arises when we use another setCount
in the increase or decrease function. The count value ideally should decrease by 2, but this won't happen.
Add this code to the counter app, and you will see that the count will increase and decrease by 1 only:
const increase = () => {
setCount(count + 1);
setCount(count + 1);
};
const decrease = () => {
setCount(count - 1);
setCount(count - 1);
};
If we want to increase or decrease the count by 2, then we should pass a callback function:
const increase = () => {
setCount((prevCount) => prevCount + 1);
setCount((prevCount) => prevCount + 1);
};
const decrease = () => {
setCount((prevCount) => prevCount - 1);
setCount((prevCount) => prevCount - 1);
};
Here, setCount
takes a callback function that will track the previous value of count
and then increase or decrease the count value.
Note: We passed 0
as a default value. Since 0
is a hard-coded value, it will run every time the component renders. To avoid rendering 0
every time, pass a callback function that will return 0
:
import { useState } from "react";
function value() {
console.log("render");
return 0;
}
export default function App() {
const [count, setCount] = useState(value());
const increase = () => {
setCount((prevCount) => prevCount + 1);
setCount((prevCount) => prevCount + 1);
};
const decrease = () => {
setCount((prevCount) => prevCount - 1);
setCount((prevCount) => prevCount - 1);
};
return (
<div>
<h1>count : {count}</h1>
<button onClick={decrease}>-</button>
<button onClick={increase}>+</button>
</div>
);
}
useState(value())
and useState(0)
both work in the same way. Here, the value function will return 0
and log "render" every time. To avoid calling "render" every time, write useState(() => return 0)
. It will render only one time.
- useEffect
useEffect is used to perform side effects in components and is imported from the React module. By "side effects," we mean tasks such as fetching data or updating the DOM, etc.
useEffect takes two arguments: a function and optional dependencies (an array).
import { useEffect } from 'react';
useEffect(() => {
//code
}, [dependencies]);
The dependencies array ensures when the effect will re-run.
There are three cases of dependency arrays:
- No dependency array :
useEffect
will be called every time. Let's seeuseEffect
in action:
import { useEffect, useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
useEffect(() => {
setTimeout(() => {
setCount((count) => count + 1);
console.log("called");
}, 2000);
});
return (
<div>
<h1>Count is called {count} times.</h1>
</div>
);
}
Here, after every 2 seconds, the count
will increase by 1, and "called" will be logged in the console.
- Empty dependency array [] :
useEffect
will be called once,during initial render.
import { useEffect, useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
useEffect(() => {
setTimeout(() => {
setCount((count) => count + 1);
console.log("called");
}, 2000);
}, []);
return (
<div>
<h1>Count is called {count} times.</h1>
</div>
);
}
In the above code , we added an empty dependency array []
.Now, useEffect
will run only one time.
- Some value passed in the dependency array:
useEffect
will be called every time whenever the value passed in the dependency array changes. We can pass any number of values in the dependency array.
import { useEffect, useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
useEffect(() => {
setTimeout(() => {
setCount((count) => count + 1);
console.log("called");
}, 2000);
}, [count]);
return (
<div>
<h1>Count is called {count} times.</h1>
</div>
);
}
In the above code, count
is passed in the dependency array. So whenever count
is updated, useEffect
will be called again. In the above code, the count
will increase infinitely as every time count
is updated, useEffect
will be called again, and this will go on and on.
There is an effect cleanup function, which will stop the useEffect
re-execution, as there may be a memory leak problem. The cleanup ensures that no unexpected behaviour occurs.
import { useEffect, useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
useEffect(() => {
const timer = setTimeout(() => {
setCount((count) => count + 1);
console.log("called");
}, 2000);
return () => clearInterval(timer);
}, [count]);
return (
<div>
<h1>Count is called {count} times.</h1>
</div>
);
}
Note: useEffect
will at least run once in the initial render.
Top comments (0)