React has brought significant changes to front-end development, especially with the advent of hooks in version 16.8. Among them, the hook has revolutionized how we handle side effects in our functional components. useEffect In this guide, we'll demystify , its use cases, and how it has made side effects management a breeze compared to the lifecycle methods of class components. useEffect Getting to Know useEffect The hook is a built-in React hook that allows us to perform side effects in our functional components. Side effects could be anything ranging from fetching data, subscribing to services, or even directly manipulating the DOM. The beauty of is its ability to encapsulate the functionalities of , , and into a single, easy-to-use API. useEffect useEffect componentDidMount componentDidUpdate componentWillUnmount For those who remember the older , here is how these lifecycle methods were used: class components class OldComponent extends React.Component { componentDidMount() { // Executed once after the initial rendering } componentDidUpdate(prevProps, prevState) { // Executed after each update } componentWillUnmount() { // Executed just before the component is unmounted and destroyed } render() { // Component's UI } } With , we achieve the same functionalities, but now within a functional component: useEffect function NewComponent() { useEffect(() => { // Replaces componentDidMount and componentDidUpdate return () => { // Replaces componentWillUnmount }; }); // Component's UI } The hook is used as follows: useEffect useEffect(() => { // Your side effect code... }, [dependency]); The first argument is a function that contains the side effect. The second argument is an array of dependencies; the effect will only rerun if any of these dependencies have changed since the last render. If you provide an empty array ( ), the effect will only run once after the initial render, similar to . [] componentDidMount useEffect and Cleanup can return a cleanup function, which is run when the component is unmounted or before the component re-runs the effect due to dependency changes. This cleanup is crucial for situations where you need to remove subscriptions or event listeners to avoid memory leaks. useEffect Here's an example of how cleanup can be done: useEffect(() => { const subscription = someService.subscribe(); return () => { // Cleanup action subscription.unsubscribe(); }; }, []); In this code, sets up a subscription when the component mounts. The cleanup function runs when the component unmounts, canceling the subscription and preventing potential memory leaks. someService.subscribe() subscription.unsubscribe() Diving Deeper with a Practical Example To further understand in action, we'll analyze a practical example in two stages. useEffect Stage 1: We begin with a simple setup involving two components, and . App Child import React, { useState, useEffect } from 'react'; import ReactDOM from 'react-dom'; function App() { const [count, setCount] = useState(1); console.log(1); useEffect(() => { console.log(4); }, []); return <Child count={count} />; } function Child({ count }) { useEffect(() => { console.log(5); return () => { console.log(6); }; }, [count]); return null; }; const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<App />); In this code, is run at the initial render of . The hook then registers . The component then returns with , which triggers the rendering of . console.log(1) App useEffect console.log(4) App Child count=1 Child Inside , registers as has changed. This effect is then executed--logging to the console. Child useEffect console.log(5) count 5 After finishes rendering, React goes back to and runs as defined in the hook. Child App console.log(4) useEffect Here is the console output for this scenario: 1 5 4 Stage 2: Next, let's add more complexity to our components by including additional effects: import React, { useState, useEffect } from 'react'; import ReactDOM from 'react-dom'; function App() { const [count, setCount] = useState(1); console.log(1); useEffect(() => { console.log(2); return () => { console.log(3); }; }, [count]); useEffect(() => { console.log(4); setCount(count => count + 1); }, []); return <Child count={count} />; } function Child({ count }) { useEffect(() => { console.log(5); return () => { console.log(6); }; }, [count]); return null; }; const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<App />); The additional in logs to the console and includes a cleanup function logging . useEffect App 2 3 After finishes rendering, React goes back to and runs , which is followed by an update to causing a rerender of and . Child App console.log(4) count App Child During the rerender, the cleanup functions for in and are run, logging and respectively. Then, and are rendered again with the new , logging , , and to the console. useEffect App Child 3 6 App Child count 1 2 5 Here's the resulting console output for this enhanced scenario: 1 5 2 4 1 3 6 5 2 Wrapping Up The hook brings significant simplicity and versatility to handling side effects in functional components. By understanding how and when is run, you can leverage it to simplify your components and make your side effect management more efficient. useEffect useEffect React While is powerful, it requires a deep understanding of its dependencies and execution order to use effectively. Mastering can give you a greater level of control over your components and how they interact with your application's data and the outside world. useEffect useEffect Whether you're migrating old class components or writing new functional components, understanding is a crucial part of modern React development. useEffect