DEV Community

Cover image for A Succinct Explanation of React.useEffect() Hook
Olatunde Adedeji
Olatunde Adedeji

Posted on • Edited on

A Succinct Explanation of React.useEffect() Hook

React.useEffect() is one of the coolest dudes among React Hooks. If you have been hooked into the world of functional components, this will definitely look familiar else you are probably still deep-necked down into the legacy React applications. You might need some functional React components pills! I must say the team behind React library are aggressively advocating for the use of functional and the Hooks approach to React applications development. It is certainly worth the effort going the Hooking way!

Anyway, useEffect helps React developers appear smarter than they are, taking care of side effects in functional React components with its simplistic touch of syntax constructs.

useEffect(() => { 
    console.log (Runing side effects) 
}) 
Enter fullscreen mode Exit fullscreen mode

Note: This runs every time component renders! You might not want this in reality.

If you like hooking up (no pun intended)- I mean with functional components, I am here to explain how you can do it well with the right understanding. In this article, you will learn and understand how, plus when to use useEffect() Hook.

What is a Hook?

Hooks are special function that allow you to hook into React state and lifecycle methods in functional components. Basically, functional and class approaches are the two major ways to develop a component in React. Hooks work only with the functional components approach. If you stumble on any Hooks in a class component, kindly raise genuine alarm. Something is definitely wrong.

useEffect() handles side effects

The purpose of useEffect() is to handle and mange side effects. And what are these side effects? Side effects are any operation in a function that is not directly related to the final output of the function. If you have probably wanted to fetch data from an API or other data source, ever wanted to tinker with DOM manually in React applications or have a subscription service set up to listen to an emitted event, all these and more are side effects in real life React.

Let‘s take a look at this side-effect of a function using document.title to display name information on a browser.

import React from 'react'; 

function App() { 

  return ( 

    <div> 

   <SayGreeting name="Olatunde"/> 

  </div> 

  ); 

} 

const SayGreeting = (name) => { 

  const greeting= `You welcome, ${name}!`; 

  // Side-effect with DOM manipulation! 

  document.title = `Greetings to ${name}`; 

  // Main expected function output 

  return <div>{greeting}</div>; 

  } 

export default App; 
Enter fullscreen mode Exit fullscreen mode

In the preceding snippet, we have a component SayGreeting with a side effect of document.title = Greetings to ${name}; This is obviously a wrong way to add a side-effect to a component. You would rather hand this over to useEffect to handle.

Let's refactor our snippet with useEffect () to manage the side effect of the component:

const SayGreeting = (name) => {  

const greeting= `You welcome, ${name}! `;  

   useEffect(() => {   

   document.title = `Greetings to ${name}`; //Side-effect with DOM manipulation inside useEffect()!  

  }, [name]);  

  // Main expected function output  

  return <div>{greeting}</div>;  

  } 
Enter fullscreen mode Exit fullscreen mode

Essentially, components are the basic building block of any React application. So, for any expression of a user interface, at least a component is rendered. The useEffect() can be used to handle the logical part of component while allowing the component to focus on the rendering part. And since we can’t tell React how many times a component should be rendered, we can clearly control how the side effects of any component should be handled in case a component chooses to render multiple times. We can control how the side effects of a component are managed with the useEffect() optional dependency argument.

Intrinsically, a component is capable of two things: rendering and handling side-effects. It is always the best practice to leave the handling of side effects to useEffect().

How to pass argument to useEffect()

The useEffect() hook graciously accepts two arguments: useEffect(callback, [dependencies]);

*The callback is the function containing the side-effect logic.

*The dependency represents optional array of dependency or dependencies.The useEffect() executes callback every time the dependencies change.
This explains the default scenario of useEffect()

useEffect(() => {  
    // Runs every time the component renders  
})  

useEffect(() => {  
    // Runs only on initial render  
}, []) // Optional second argument: dependency array  

useEffect(() => {  
    // Runs only when 'OptionalDataValue' changes  
}, [OptionalDataValue]) 
Enter fullscreen mode Exit fullscreen mode

Fetching data from an endpoint over a network

Let’s dive into how the useEffect() performs data fetching side effect.

The following component FetchUsers fetches the users list over a specified endpoint on the network:

import React,{useEffect,useState} from 'react';  

function App() { 

  return ( 

    <div>  

   <FetchUsers /> 

  </div> 

  ); 

}  

  function FetchUsers() {  

    const [users, setUsers] = useState([]);  

    useEffect(() => {  

      async function fetchUsers() {  

        const response = await fetch (' https://mocki.io/v1/d4867d8b-b5d5-4a48-a4ab-79131b5809b8');  

        const fetchedUsers = await response.json(response);  

        setUsers(fetchedUsers);  

      }  

      fetchUsers();  

    }, [users]); 

     return (  

      <div>  

        {users.map((user) => <div key={user.name}>{user.name}</div>)}  

      </div>  

    );  

   }  

export default App; 

Enter fullscreen mode Exit fullscreen mode

The useEffect() starts a fetch request by calling an async function fetchUsers() after the initial componentDidMount.

When the request completes, setUsers(fetchedUsers) updates the users current state with the already fetched users list.

We set an empty array [] dependency to indicate the useEffect() should run once component is mounted and if any dependency was added to the array which could be a prop or state value-[users]. We will only re-run the useEffect() once the users list changes.

useEffect() and Component lifecycle methods

Components in React undergo three major phases; mounting, updating and unmounting. This explains the relationship of component with the DOM tree. You should be familiar with how React use Virtual DOM on top of the native browser DOM to smartly update the DOM on any state change. This is one of the innovative ideas of React.

So, when the component is mounted on the DOM, componentDidMount() is invoked to perform its side effect operation which could be network requests or mutations in the DOM as explained earlier.

componentDidMount() { 

Console.log (component mounted successfully); 

 } 

Enter fullscreen mode Exit fullscreen mode

The useEffect() encapsulates the componentDidMount(), componentDidUpdate() and componentWillUnmount()

We will be examining how the useEffect() handle stages in the component lifecycle methods.

Component did mount

With componentDidMount():

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

This runs when the component mount and it runs on every component re-rendering.

We can also look at this:

useEffect(() => {  
console.log("componentDidMount");  
}, []); 
Enter fullscreen mode Exit fullscreen mode

In the preceding, an empty second argument array is passed. This means when the component mount and the useEffect() runs once as well. This doesn’t re-run the useEffect() at every re-rendering.

Component will update

With componentWillUpdate():

useEffect(() => {  

console.log("componentWillUpdate"); 

 }, [args]); 
Enter fullscreen mode Exit fullscreen mode

The second argument is passed to the useEffect() and any state or props value change will cause the component to update.

Component will unmount

With componentWillUnmount():

useEffect(() => {  

  return () => { 

 console.log("componentWillUnmount"); 

  }; 

 }, [args]);  
Enter fullscreen mode Exit fullscreen mode

With the return function running after the side effect, you have a cleanup mechanism to handle the side effect before being re-mounted.

In conclusion,

The useEffect is an important Hook in functional component. We have seen how useEffect() helps with handling of side-effects. Apart from managing side effects, useEffect() Hook enables us to further separate concerns within the component by handling the logical code in component while component faces the task of rendering.

Also with useEffect Hook, we have a lean way of capturing component lifecycles and methods in our React applications regardless of components complex states.

Kindly let me know what you feel about the information on useEffect() Hook, is there any over look concepts or not too clear explanation of useEffect() Hook.

Top comments (0)