Rollie
Rollie

Reputation: 4752

How do hooks know when to trigger (or not trigger) the body of useEffect?

Looking at the official react docs, an example is given for writing a custom hook, as below:

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

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

    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}

function ChatRecipientPicker() {
  const [recipientID, setRecipientID] = useState(1);
  const isRecipientOnline = useFriendStatus(recipientID);

  return (
    <>
      <Circle color={isRecipientOnline ? 'green' : 'red'} />
      <select
        value={recipientID}
        onChange={e => setRecipientID(Number(e.target.value))}
      >
        {friendList.map(friend => (
          <option key={friend.id} value={friend.id}>
            {friend.name}
          </option>
        ))}
      </select>
    </>
  );
}

The part I'm confused about - my understanding is useEffect(...) will trigger each time the component re-renders, which as currently described, would only happen when setRecipientID is called. But, say another state variable is added, say, const [nameFilter, setNameFilter] = useState(''). In this case, the component will re-render every time a user types into the filter, which I think will trigger the "connection" logic in useEffect.

I think this would work if useEffect took in the friendID as the 2nd param, but being new to react I don't want to assume the official docs are not written in a resilient way, which means I'm wrong and the react plumbing somehow knows to not connect each re-render - but how?

Upvotes: 1

Views: 291

Answers (1)

Nadia Chibrikova
Nadia Chibrikova

Reputation: 5036

To useEffect you need to provide a callback that is going to be executed and, optionally, an array of values that will determine when the effect is triggered. Here you have three options:

  1. You pass nothing - useEffect is triggered each time components is rendered

  2. You pass en empty array - useEffect is triggered only once, when component is mounted

  3. You pass an array with props and state variables - useEffect is triggered when the component is first mounted and each time at least one of the variables changes

React does not do anything else to reduce the number of times useEffect is called, so yes you do need to explicitly provide variables your effect depends on (friendID in your case)

Upvotes: 1

Related Questions