Ins & Outs Of Component Lifecycle With UseEffect

As you are reading this blog, you are one of the cool developers and to become the coolest developer you need to follow the above quote.

Here, I am sharing my story, when I tried to become the coolest developer!

When I heard about hooks in React JS, I read about it and tried to write new components with hooks as functional components. – it worked perfectly! But I never tried to re-write existing class based components code by using hooks. As a developer, changing the existing working code is a scary thing.

Then I decided to replace one class based component by functional component with hooks, which has lifecycle methods such as — componentDidMount, componentDidUpdate, componentWillUnmount.

When we want to compare useEffect hook with component lifecycle, Some questions that comes in our mind are — Should we compare these two? Are they both the same?

Yes, they are almost the same! useEffect hook does allow us to write life cycle method functionality in functional components.

Same result but by easiest way !

In this article, I am assuming that you’re familiar with the hooks concept and component lifecycle methods. If you are not then please check — hooks and Adding lifecycle methods to class.

In react when we use class based components we get access to lifecycle methods, such as componentDidMount, componentDidUpdate, componentWillUnmount, etc. Functional components (before React 16.8) are purely stateless components. But in React 16.8, they have added Hooks. Hooks can be used in place of state and lifecycle methods.

The big difference comes with the implementation, in the class based component we have predefined functions for using lifecycle methods, but in function based component we implement each of those using useEffect.

Generally, We choose functional components over class based because functional components are considered faster than class based components.

From useEffect documentation —

“It accepts a function that contains imperative, possibly effectual code. The function passed to useEffect will run after the render is committed to the screen.”

React’s useEffect hook combines componentDidMount, componentDidUpdate and componentWillUnmount lifecycle methods.

Why useEffect?

  1. Reduces the amount of code.
  2. Simplifies the code.
  3. It allows us to write repetitive component lifecycle code at one place.
  4. Allows for multiple useEffect hooks to be called in a single component.

Now let’s see how we can implement lifecycle methods with useEffect.

1. useEffect

This side effect will execute on every render including when the component has mounted and every time it updates.

useEffect(() => {
    console.log('This block will executing on every render')
});

2. componentDidMount comparable useEffect

This effect will execute only once when component is just mounted. Empty array is a dependency array, which helps this effect to list its dependencies for execution. As we are passing an empty array as the second parameter, it will execute only once.

useEffect(() => {
  /* ComponentDidMount code */
  
  fetchUserApi(id).then((user) => {
     setUser(user)
  })}, []);

3. componentDidUpdate comparable useEffect

This effect will execute only once, when component is updated (includes re-rendering).

useEffect(() => {
  /* ComponentDidUpdate code */
  
  fetchUserApi(id).then((user) => {
     setUser(user)
  })}, [id]); 

Watch out !

We just saw that useEffect executes when the component has mounted and every time it updates. So it works similarly to the old componentDidMount() and componentDidUpdate() methods for class components.

There is a tiny problem, though.

Did you observe? — The useEffect block written for componentDidUpdate() will also execute for componentDidMount(). But what if we want to execute only when the component mounts or only when it updates. Sometimes, we might not want it to work like both componentDidMount() and componentDidUpdate()

One solution can be with a reference hook.

How does the reference hook help us?

We can use the reference to check whether the component has just mounted or updated. We initialize it as false and change the state to true on the first render. Then, we use this information to decide whether our useEffect should do something or not.

const App = props => {
  const didMountRef = useRef(false)
  useEffect(() => {
    if (didMountRef.current) {
      doStuff()
    } else {
      didMountRef.current = true
    }
  }
}

This hook will check if didMountRef.current is true. If it is, it means that the component has just updated and therefore the hook needs to be executed. If it’s false, then it means that the component has just mounted, so it will skip whatever action it is supposed to perform and set the value of didMountRef.current to true to know that future re-renderings are triggered by updates.

4. componentWillUnmount comparable useEffect

This effect will execute only once when component is unmounted. There are two important cases we should know —

  1. If we want cleanup function to run only when the component has unmounted, we need to set an empty array.
  2. If we set one or more variables in the dependency array, cleanup will run at every re-render.
useEffect(() => {
  return () => {
    /* componentWillUnmount code */
    setUser(null)
  }
}, []);

5. All three combined

useEffect(() => {  /* componentDidMount + componentDidUpdate */  fetchUserApi(id).then((user) => {
     setCurrentUser(user)
  })return () => {
   /* componentWillUnmount code */
    setCurrentUser(null)
  }
}, [id]);

6. shouldComponentUpdate comparable hook

For shouldComponentUpdate, we can use React.memo —

when the function returns true, the component will not be re-rendered.

const areEqual => (prevProps, nextProps) => {
   return prevProps.userId === nextProps.userId
}const User = React.memo(Component, areEqual);

Thank you for taking time to read this article.

Happy Coding!

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.