DEV Community

Cover image for understanding React Hooks and Effects
Dan L.
Dan L.

Posted on

understanding React Hooks and Effects

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

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

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

React Effects are normally triggered by React after each RENDER of the component.

An effect can contain also a cleanup method by returning it from the callback function like this

useEffect(() => {
  AppAPI.subscribeToNameChange(nameChanged);

  document.title = "name is ${name}"

  return () => {
    AppAPI.unsubscribeToNameChange(nameChanged);
  }
});
Enter fullscreen mode Exit fullscreen mode

Multiple hooks can be used to separate concerns:

function FriendStatusWithCounter(props) {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });
  // ...
}
Enter fullscreen mode Exit fullscreen mode

useEffect lifecycle

An important thing to note is the effect callbacks are applied at both lifecycles of init/destroy and after each render.
It is helpful because each state change should produce a consistent refresh of the component's UI.
This feature is provided out of the box, while for class based React components this needs to be addressed manually via componentDidUpdate.
Also any listeners bound during the effect's execution are likely to be linked to the current state of the component. So if the state changes, these listeners should be rebound:

function FriendStatus(props) {
  // ...
  useEffect(() => {
    // ...
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });
Enter fullscreen mode Exit fullscreen mode

However this is prone to performance issues if the callback execution is expensive.
To help with that, React provides a dirty check feature, by providing an extra param to useEffect:

useEffect(() => {
  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
  return () => {
    ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
  };
}, [props.friend.id]); // Only re-subscribe if props.friend.id changes
Enter fullscreen mode Exit fullscreen mode

Source: https://reactjs.org/docs/hooks-effect.html

Top comments (0)