Lesson 10 - `UseEffect` Hook

10.1 - Managing Side Effects With UseEffect

The useEffect is one of the most powerful and important hooks in React. It allows you to perform side effects in your functional components, such as data fetching, subscriptions, and manually changing the DOM.

For instance, you might fetch JSON data from another server. When this JSON data updates on the server, it triggers a side effect. useEffect tracks these changes and re-renders the UI to reflect the updated data.

These side effects could be internal like form submission, updating state variables, or refreshing resources, each quietly shaping the flow of your application.

Managing a functional component's lifecycle with the useEffect hook contains three phases:

  1. Mounting: This is the initial step when a component is rendered for the first time. The effect runs after the initial render when the dependency array is empty.    
  2. Updating: In this phase the component updates itself due to changes in state or props. The effect runs after every re-render if there are no dependencies, or when specified dependencies change.    
  3. Unmounting: This is the last phase when a component is removed from the DOM. the cleanup function inside useEffect runs before the component unmounts to clean up side effects like subscriptions or timers.

When it's about managing side effects, you have a few ways to do that.

Dependent Mode: In dependent mode, the useEffect hook executes depending on a specific state. The useEffect hook only runs if the current state is changed.

For example,

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

function App() {
 const [count, setCount] = useState(0);
 const [num, setNum] = useState(0)

 useEffect(() => {
 document.title = `Count is now ${count}`;
 },[count]);

 return (
 <>
 <p>You clicked {count} times</p>
 <button onClick={() => setCount(count + 1)}>Update Count</button>
 <button onClick={() => setNum(num + 1)}>Update Num</button>
 </>
 );
}

In the example above, there are two states count and num. The useEffect hook depends on state count and only executes only if its current state is changed.  

Independent Mode: In this mode, the useEffect hook runs on every render that happens on the webpage. In this way, you don't have any control over the execution of the useEffect hook.

Have a look at the following example:

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

function App() {
 const [count, setCount] = useState(0);

 useEffect(() => {
 setTimeout(() => {
 setCount((count) => count + 1);
 }, 1000);
 });

 return (
 <>
 <p>Page rendered {count} times!</p>
 </>
 );
}

The useEffect hook in this example executes every second since the state count changes continuously.

Single Run mode: In this mode, the useEffect hook runs once at the beginning of the page load. This is helpful when you need some additional rendering during the page load.

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

function App() {
 const [num, setNum] = useState(0);

 useEffect(() => {
 document.title = `Num is ${num}`;
 },[]);

 return (
 <>
 <p>Num is {num}</p>
 <button onClick={() => setNum(num + 1)}>Update Num</button>
 </>
 );
}

In the above example, the useEffect runs once during page load. If you update the state num using the button Update Num, you can observe that the useEffect isn't executed.