DEV Community

Cover image for UseState and UseEffect Hooks of React
Sobhan Dash
Sobhan Dash

Posted on

UseState and UseEffect Hooks of React

TOC:

  1. What are hooks?
  2. useState hook
  3. useEffect hook

What are hooks?

Before we start with the specific hooks mentioned above in the title, we first need to know what are hooks?
Imagine a fishing rod, you have a hook at the end to grab fish, right? React Hook do the same but with states and lifecycle methods. Hooks were introduced in React 16.8, allowing functional components to get access to the states and lifecycle methods. Because of hooks, we don’t have the use of class components anymore. Trust me escape from ‘this’ hell is much rewarding that getting an ice-cream in a hot summer day.
Run from this keyword
Now React hooks start from a “use” keyword. Ex- useState(), useEffect(), useFetch(). The first two are prewritten hooks from React, last one is something called as a custom hook. We will get know about them in a later post.
The component names must start with an Uppercase letter in order to use any type of hook. These hooks need to stay inside the component/function body and we can’t call hooks conditionally.

useState hook

So, coming back to the initial topic. We can import the hooks or directly declare it using React.hookName.

// Three ways to import hooks
import React, {useEffect} from react;
import useFetch from ./useFetch;
const [show, setShow] = React.useState(false);
Enter fullscreen mode Exit fullscreen mode

In useState hook there are two parts declared inside square parts. First is the state itself and the second is a function that changes the value of the state. In simple terms handles the changes in the state. From above show is the state and setShow is the function.
useState is one of the most commonly used hooks in React. Now there are multiple approach to setting the value of the state using the function. For example:

setFruit((oldFruit) => {
    let newFruits = oldFruit.filter((fruit)=> fruit.id !== id);
    return newFruits;
} 
// the above is same as
let newFruits = oldFruit.filter((fruit)=> fruit.id !== id);
setFruit(newFruits)
Enter fullscreen mode Exit fullscreen mode

So that essentially concludes the basic useState hook, eventually advanced concepts such as useReducer hook and Redux take over what useState does on simple terms and build upon that.
Yeah!

useEffect hook

The useEffect hook helps create side effects in the app which means that any action that is not on the main component or something that should run in the background and not on the view of the app.
Some examples would be the popups that you see visiting a website, signing up for subscription, setting up an eventListener and most commonly used to fetch data from the server.

Fun Fact: if you ever encounter double render of data in your console then it is due to React.StrictMode in the index.js file.

useEffect(() => {
    console.log(call useEffect);
})
Enter fullscreen mode Exit fullscreen mode

Now, the hook is acting like a function which is re-rendered almost infinitely. So, useEffect can take another parameter along with the initial function and that is an array, called the Dependency array. We can send one or more states or functions to the dependency array. The array is denoted as ‘[]’, when left empty the useEffect is run only once at the initial render.

useEffect(()=>{
    fetchApi.then(()=>{
    setLoading(false)
})
}, [])
Enter fullscreen mode Exit fullscreen mode

It restricts the re-render almost every time but we might encounter an infinite loop from the function that has been passed in the dependency array. So we need a cleanup function. And the keyword “cleanup” is important as React automatically searches for it in a useEffect.
The Flow of useEffect with cleanup function is something like :
(Initial Render + useEffect() call) --> (Re-Render + Cleanup Function + useEffect() call) --> (Re-Render + Cleanup Function + useEffect() call)…
Below is an example for a useEffect where we show a loading gif or pic until the data is fetched. We also are checking if the component is still mounted. This way we prevent memory leaks

function myComp(){ 
    const [loading, setLoading] = useState(true)
useEffect(()=>{
    let mounted = true
        apiFetch.then(()=>{
            if(mounted){
            setLoading(false)
        }
})
return function cleanup(){
        mounted = false
} 
}, [])
return <div> {loading ? <p>Loading…</p> : <p>Data Fetched</p> } </div>
}
Enter fullscreen mode Exit fullscreen mode

Notes while Fetching Data:

Remember to never call useEffect using async await. They return a promise while useEffect is looking for a cleanup function. We can use async await inside useEffect but not the hook itself.

//Wrong
useEffect(async () => {
//code
});
//Correct
useEffect(() => {
async //code;
});
//Alternatively
const fnName = async() => { 
    //code
}
useEffect(() => {
    fnName()
},[])

Enter fullscreen mode Exit fullscreen mode

See you in the next part of the series! Do let me know your thoughts and follow my Twitter and LinkedIn.

Top comments (0)