9:12 pm 2/22/22

A little note as to why useEffect's do not properly update the state if you don't update state based on the current state. For example:

            
function Component() {
  let [lst, setLst] = useState([]);
  useEffect(() => {
    [1, 2, 3, 4, 5].map(n => setList([...lst, n]));
  }, []);
  return (
    <div>
      {lst.map(item => 
        <div key={"item: " + item}>
          {item}
        </div>
      )}
    </div>
  )
}
            
          

If you run this code, the only item that will be in the list is 5.

The reason that the list has only 5, is because of closures. You are also probably thinking (or at least I was) that even if it was a closure, if we are calling setState (setLst), shouldn't the lst variable be updated since the lst was in a higher scope and we are updating and accessing that same variable?

The reason is because everytime (not necessarily everytime because React might batch together setState calls for optimization reasons) you call setState (setLst), the component function, Component, gets rerendered and your component is recalled (something like Component() or React.createElement(Component). I don't know the specifics). Once our component is rerendered, a new closure is created and so the useEffect function that you passed in previously, is referring to an old closure that holds an outdated version of lst. Which is why lst contains just 5 because in the old closure, lst is only equal to [] (an empty list).

In order to fix this problem, we need to change

[1, 2, 3, 4, 5].map(n => setLst([...lst, n]))
to
[1, 2, 3, 4, 5].map(n => setLst(currentLst => [...currentLst, n]))

So instead of referring to an old closures version of lst, we use the current state of lst (currentLst), to update our state which leads to a correct list that includes the numbers 1-5.