Can a React usestate update be nested in another useState functional update?

428 views Asked by At

There are n items the user can vote on. There are two React states:

  • votes is an array of the user's votes on every item.

    const [votes, setVotes] = useState({});

  • voteChanges indicates how many times the user changed their votes on any of the items.

    const [voteChanges, setVoteChanges] = useState(0);

We have a database listener defined in a useEffect. When votes are added/changed in the database, the listener gets called. We need the state votes to compare every new vote with its previous value in votes to decide whether to increment voteChanges. However, we cannot define votes as a dependency in useEffect, otherwise we will end up in an infinite loop. To get access to the current value of votes, we use its functional update. Is it okay to call setVoteChanges inside the functional update of setVotes? If no, why, and how would you solve this problem?

  useEffect(() => {
    databaseListener((changes) => {
      setVotes((oldVotes) => {
        const oVotes = { ...oldVotes };
        for (let change of changes) {
          const itemId = change.id;
          const newVote = change.vote;
          if (oVotes[itemId] !== newVote) {
            setVoteChanges(oldCount => oldCount + 1);
          }
          oVotes[itemId] = newVote;
        }
        return oVotes;
      });
    });
  });

This simple React App shows the complete code.

Related Job offer: We offer an interview spot to every developer who correctly solves this problem for a US-based full-time position. Check out the full description at: https://www.upwork.com/jobs/~011fff0479dbd2b3e5

1

There are 1 answers

1
Krystian Sztadhaus On

To fix your issue you need to prevent re-call a databaseListener each render. You can do that by using an empty array as a dependency.

useEffect(() => {
  databaseListener(event => {
    ...
  })
}, [])

Please take a look at my quick example https://jsfiddle.net/h6tmeksr/1/

Is it okay to call setVoteChanges inside the functional update of setVotes?

Yes, because React has a batch update mechanism ( version 17 )