Does React useState's setter ever get stale?

Viewed 59

I'm using global event handlers. To avoid detaching/reattaching the event handlers every time the state changes, I'm using a ref with forced updates:

  const ref = useRef();
  const forceUpdate = useState()[1];

  const handlePopState = (event) => {
    ref.current = {
      ...ref.current,
      foo: event.foo,
    };
    forceUpdate();
  };

  useEffect(() => {
    window.addEventListener('popstate', handlePopState);

    return () => {
      window.removeEventListener('popstate', handlePopState);
    };
  }, []);

I was surprised this actually works. Technically, forceUpdate is using a stale version of useState's setter, but that doesn't seem to cause errors.

Is it safe to use a stale version of useState like this? If not, what issues could this cause?

1 Answers

Is it safe to use a stale version of useState like this?

Yes, this is how you you implement this.forceUpdate with hooks.

Typically you will see something like:

// forceRender();
const [, forceRender] = useReducer((p) => !p, false);

Its even used in react-redux source code.

Related