From 0e7da8da88a5fe5395bf900a44deab07beec4864 Mon Sep 17 00:00:00 2001 From: Anton Zhuravsky Date: Thu, 11 Jul 2024 09:17:51 +0100 Subject: [PATCH] Making sure models created with useLocalStore stop updating the state on update (#914) Co-authored-by: Anton Zhuravsky --- src/use-local-store.js | 2 +- tests/use-local-store.test.js | 51 ++++++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/use-local-store.js b/src/use-local-store.js index 4ef0cffd..e9aba19f 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); diff --git a/tests/use-local-store.test.js b/tests/use-local-store.test.js index 9b960b31..7abcbd83 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(); + + // capture action from *current* model instance + const {up} = currentActions; + + // ASSERT + expect(currentState).toEqual({ + count: 0, + }); + + // ACT + rerender(); + + // ASSERT + expect(currentState).toEqual({ + count: 0, + }); + + // invoke "old" action – since we re-rendered the model it should be no-op + act(() => { + up(); + }); + + // ACT + rerender(); + + // ASSERT + expect(currentState).toEqual({ + count: 0, + }); +});