DEV Community

Lu Yu
Lu Yu

Posted on

2 2

Stale closure: Why did my setState only triggered twice?

I' trying to build a toast message API for React. My goal is to provide a fireNotification() api that can be called anywhere in the app and have React render the toast component.

I built this simple notification manager with sub/pub pattern and hope to be able to subscribe to new notifications in a useEffect hook

const notifications = [];

const listeners = new Set();

function subscribe(callback) {
  listeners.add(callback);
}

function publish() {
  listeners.forEach((cb) => {
    cb(notifications);
  });
}
export function fireNotification(content) {
  notifications.push(content);
  publish();
}

export default function App() {
  const [state, setState] = React.useState();
  React.useEffect(() => {
    subscribe((updated) => {
      setState(updated);
    });
  }, []);

  // state will be logged correctly 2 times
  // won't be updated after that
  console.log("state", state);
  return (
    <div className="App">
      <button onClick={() => {fireNotification('test')}}>fire</button>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

codesandbox

However, fireNotification() will only trigger setState twice

From the 3rd time onward, the state is not updated at all.

I'm able to make state update work by changing setState(updated) to setState([...updated]), but not sure why it works.

Can someone explain why setState(updated); only triggers twice? Thanks!

Sentry blog image

How to reduce TTFB

In the past few years in the web dev world, we’ve seen a significant push towards rendering our websites on the server. Doing so is better for SEO and performs better on low-powered devices, but one thing we had to sacrifice is TTFB.

In this article, we’ll see how we can identify what makes our TTFB high so we can fix it.

Read more

Top comments (0)

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay