Repository: ctrlplusb/easy-peasy
Pull request #914 (2024-07-09 13:24:10)

Making sure models created with useLocalStore stop updating the state on update
As described in https://github.com/ctrlplusb/easy-peasy/issues/913, when a model created by `useLocalStore` is re-created due to dependency array change, it won't unsubscribe itself and will continue delivering state updates to (now new) model.

The test case added in this PR demonstrates exactly that (fails on current `master`, works in this branch).

vercel[bot]: [vc]: #ADqwe0cPfd+GBtNwR7PdtJMkH5LwrESpIQ7T9vwV96Y=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJlYXN5LXBlYXN5Iiwicm9vdERpcmVjdG9yeSI6IndlYnNpdGUiLCJpbnNwZWN0b3JVcmwiOiJodHRwczovL3ZlcmNlbC5jb20vc2Vhbi1tYXRoZXNvbnMtcHJvamVjdHMvZWFzeS1wZWFzeS9HaTNwWE11aFJTRFVOeWUzZGc5Nnk2dVdBOHZ5IiwicHJldmlld1VybCI6ImVhc3ktcGVhc3ktZ2l0LWZvcmsteWFyZC1idWctdXNlLTcxMTUxYi1zZWFuLW1hdGhlc29ucy1wcm9qZWN0cy52ZXJjZWwuYXBwIiwibmV4dENvbW1pdFN0YXR1cyI6IlBFTkRJTkciLCJsaXZlRmVlZGJhY2siOnsicmVzb2x2ZWQiOjAsInVucmVzb2x2ZWQiOjAsInRvdGFsIjowLCJsaW5rIjoiZWFzeS1wZWFzeS1naXQtZm9yay15YXJkLWJ1Zy11c2UtNzExNTFiLXNlYW4tbWF0aGVzb25zLXByb2plY3RzLnZlcmNlbC5hcHAifX1dfQ==
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)

| Name | Status | Preview | Comments | Updated (UTC) |
| :--- | :----- | :------ | :------- | :------ |
| **easy-peasy** | 🔄 Building ([Inspect](https://vercel.com/sean-mathesons-projects/easy-peasy/Gi3pXMuhRSDUNye3dg96y6uWA8vy)) | [Visit Preview](https://vercel.live/open-feedback/easy-peasy-git-fork-yard-bug-use-71151b-sean-mathesons-projects.vercel.app?via=pr-comment-visit-preview-link&passThrough=1) | 💬 [**Add feedback**](https://vercel.live/open-feedback/easy-peasy-git-fork-yard-bug-use-71151b-sean-mathesons-projects.vercel.app?via=pr-comment-feedback-link) | Jul 9, 2024 1:24pm |



Patch:
diff --git a/src/use-local-store.js b/src/use-local-store.js
index 4ef0cff..e9aba19 100644
--- a/src/use-local-store.js
+++ b/src/use-local-store.js
@@ -28,7 +28,7 @@ export function useLocalStore(
 
   useEffect(() => {
     setCurrentState(store.getState());
-    store.subscribe(() => {
+    return store.subscribe(() => {
       const nextState = store.getState();
       if (currentState !== nextState) {
         setCurrentState(nextState);


Test patch:
diff --git a/tests/use-local-store.test.js b/tests/use-local-store.test.js
index 9b960b3..7abcbd8 100644
--- a/tests/use-local-store.test.js
+++ b/tests/use-local-store.test.js
@@ -1,5 +1,5 @@
 import React from 'react';
-import { render, fireEvent } from '@testing-library/react';
+import { render, fireEvent, act } from '@testing-library/react';
 import { useLocalStore, action } from '../src';
 
 function CountDisplay() {
@@ -300,3 +300,52 @@ test('updates the store if a dependency changes', () => {
     count: 200,
   });
 });
+
+test('stops propagating state update when dependencies change', () => {
+  // ARRANGE
+  let currentState;
+  let currentActions;
+
+  // eslint-disable-next-line no-shadow, react/prop-types
+  function CountDisplay({ version }) {
+    [currentState, currentActions] = useLocalStore(() => ({
+      count: 0,
+      up: action((state) => {
+        state.count = 137;
+      })
+    }), [version]);
+    return null;
+  }
+
+  // ACT
+  const { rerender } = render(<CountDisplay version={1} />);
+
+  // capture action from *current* model instance
+  const {up} = currentActions;
+
+  // ASSERT
+  expect(currentState).toEqual({
+    count: 0,
+  });
+
+  // ACT
+  rerender(<CountDisplay version={2} />);
+
+  // ASSERT
+  expect(currentState).toEqual({
+    count: 0,
+  });
+
+  // invoke "old" action – since we re-rendered the model it should be no-op
+  act(() => {
+    up();
+  });
+
+  // ACT
+  rerender(<CountDisplay version={2} />);
+
+  // ASSERT
+  expect(currentState).toEqual({
+    count: 0,
+  });
+});