Search code examples
reactjsasynchronousref

React ref doesn't update on async set


Anyone how can tell me why the ref doesn't get updated on the initial render?

I am setting the ref conditionally on the last item, which work fine if I don't set the values async.

const [values, setValues] = useState<Array<Number>>([]);
  const ref = useRef(null);

  useEffect(() => {
    console.log(ref.current);
  }, [ref]);

  useEffect(() => {
    setTimeout(() => {
      const newValues = Array(10)
        .fill(0)
        .map((item) => Math.random());
      setValues(newValues);
    }, 1000);
  }, []);

  return (
    <div className="App">
      {values.map((value, index) => {
        const isLast = index === values.length - 1;
        return (
          <div key={value.toString()} {...(isLast && { ref: ref })}>
            {value}
          </div>
        );
      })}
    </div>
  );

Codesandbox


Solution

  • The reason why you don't see useEffect witth dependency as ref executed when you populatee the values async is because the ref instance remains same but the current key within tthe ref object is modified.

    If you track on ref.current, you will see the useEffect get executed.

      useEffect(() => {
        console.log(ref.current);
      }, [ref.current]);
    

    However that is not the right approach because a change in ref is not triggering a re-render and useEffect is called post a re-render. What you should instead rely on as a dependency for your useEffect is a change in values which essentially causes the ref to change

      useEffect(() => {
        console.log(ref.current);
      }, [values]);
      
    

    DEMO sandbox