suren-atoyan / react-pwa

Starter kit for modern web applications
https://react-pwa.surenatoyan.com/
MIT License
577 stars 132 forks source link

recoil actions in useEffect #44

Open SecretUnicorn opened 1 year ago

SecretUnicorn commented 1 year ago
function useTeams() {
  const [teamState, setTeamState] = useRecoilState(teamsAtom);

  function init(teams) {
    setTeamState(teams.map(t => ({
      ...t,
      answered: false,
      already_answered: false,
    })));
  }

  function teamAnswered(teamId) {
    setTeamState(teamState.map(t => ({
      ...t,
      answered: t.id === teamId,
    })));
  }

  return [teamState, { init, teamAnswered }];
useEffect(() => {
    if (lastMessage && lastMessage.data) {
          teamAnswered(data.data)
    }
  }, [lastMessage, teamAnswered]);

I want to change my recoil state in a useEffect. My linter tells me to add the "setTeam" function to the dep list of the useEffect. But when I use setTeam, team changes and setTeam does too which causes the useEffect to trigger endlessly. Is this intended or am I using the hook wrokng? Any help would be apreciated

suren-atoyan commented 1 year ago

@SecretUnicorn

two important things to improve here:

1) when you use setState and you need to refer to the previous state use this method:

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

...
function increment() {
  setCount(prevCount => prevCount + 1);
}

This will help you to make increment function have no dependencies (we do not consider setCount).

In your case it should be something like this:

function teamAnswered(teamId) {
  setTeamState(teamState => teamState.map(t => ({
    ...t,
    answered: t.id === teamId,
  })));
}

2) use useCallback

const teamAnswered = useCallback((teamId) => {
  setTeamState(teamState => teamState.map(t => ({
    ...t,
    answered: t.id === teamId,
  })));
}, [setTeamState]);

let me know if this helps