react js-tutorial

React useEffect Hooks

When we update a state, there can be side effects that occur in parallel with each change. Data fetch requests, direct DOM manipulations, and the use of timer functions such as setTimeout() are examples of side effects. We can use the React useEffect Hook to perform side effects in function components.

Previously, these side effects were achieved using lifecycle methods like componentDidMount(), componentDidUpdate(), and componentWillUnmount(). The useEffect Hook is a combination of all these methods. It accepts a callback function that is invoked whenever a render occurs.

Take a look at the following example to see how we can use lifecycle methods to achieve the side effects.

class Time extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }
componentDidMount() {
    setInterval(
      () => this.tick(),
      1000
    );
  }
tick() {
    this.setState({
      date: new Date()
    });
  }
render() {
    return (
      <div><h2>{this.state.date.toLocaleTimeString()}</h2></div>
    );
  }
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Time />);

In this example class component, we use the lifecycle methods to set the current time. Now, let’s consider the following example to see how the useEffect Hook can be used to replace the componentDidMount() method.

import React, { useState, useEffect } from "react";
function Time() {
  const [date, setDate] = useState(new Date());
  useEffect(() => {
    setInterval(() => {
      setDate(new Date());
    }, 1000);
  }, []);
  return <div>Time: {date.toLocaleTimeString()}</div>;
}


You can see how much easier it is to implement using Hooks rather than lifecycle methods. You can play with the code here.

In React components, there are two types of side effects: those that do not require cleanup and those that do. In the previous example, no cleanup was required. Setting up a subscription, closing a socket, and clearing timers are a few common examples of side effects that require cleanup.

So, let’s see how we can use useEffect with cleanup.

useEffect with cleanup

Cleanup in useEffect is important to prevent memory leaks.

If the useEffect() callback returns a function, useEffect() considers this to be an effective cleanup. Take a look at the following example.

import { useEffect } from 'react';
function LogMessage({ message }) {
  useEffect(() => {
    const log = setInterval(() => {
      console.log(message);
    }, 1000);
    return () => {
      clearInterval(log);
    };
  }, [message]);
  return <div>logging to console "{message}"</div>;
}

In the previous example, the cleanup function clears the interval. Rather than being called after the initial rendering, the cleanup function is called before invoking the next side-effect callback. It cleans up the previous side effect and then executes the current side effect.

If no cleanup is performed, there will be multiple console logs when only one updated log is required. Therefore, make sure to use the cleanup function in such scenarios.

Skipping effects

By default, the useEffect Hook runs after the first render as well as after each update. However, you might need to skip applying an effect in situations like when certain values haven’t changed since the last re-render.

You can easily skip applying effects by passing an array as a second argument to the useEffect Hook. As arguments, you can pass props or state values. When an argument is passed, the useEffect Hook will be executed after the initial render and only when the argument values change.

Consider the following example, in which the effect is only invoked if the variable count is updated.

useEffect(() => {
  console.log(count);
}, [count]);

If you want to run and clean up the effect only once, you can pass an empty array ([]) as the second argument.

RECOMMENDED ARTICLES





Leave a Reply

Your email address will not be published.