diff --git a/.changeset/ninety-deers-nail.md b/.changeset/ninety-deers-nail.md new file mode 100644 index 0000000..5bd7822 --- /dev/null +++ b/.changeset/ninety-deers-nail.md @@ -0,0 +1,5 @@ +--- +'ccstate-react': minor +--- + +fix: useSet should useCallback to keep stable diff --git a/packages/react/src/__tests__/get-and-set.test.tsx b/packages/react/src/__tests__/get-and-set.test.tsx index bacf36f..530e6cd 100644 --- a/packages/react/src/__tests__/get-and-set.test.tsx +++ b/packages/react/src/__tests__/get-and-set.test.tsx @@ -260,3 +260,35 @@ describe('react', () => { expect(store.getSubscribeGraph()).toHaveLength(0); }); }); + +it('useSet should be stable', () => { + const count$ = state(0); + + function Container() { + const count = useGet(count$); + return ; + } + + function Foo({ count }: { count: number }) { + const setCount = useSet(count$); + + return ( + <> + count: {count} + + + ); + } + + const trace = vi.fn(); + function RenderCounter({ setCount }: { setCount: (val: number) => void }) { + trace(setCount); + setCount(1); + return
Render
; + } + + render(); + + expect(trace).toHaveBeenCalledTimes(2); + expect(trace.mock.calls[0][0]).toBe(trace.mock.calls[1][0]); +}); diff --git a/packages/react/src/useSet.ts b/packages/react/src/useSet.ts index 24c0916..994b2fd 100644 --- a/packages/react/src/useSet.ts +++ b/packages/react/src/useSet.ts @@ -1,3 +1,4 @@ +import { useCallback } from 'react'; import { useStore } from './provider'; import type { Command, State, StateArg } from 'ccstate'; @@ -13,15 +14,14 @@ export function useSet( ): ValueSetter | CommandInvoker { const store = useStore(); - if ('write' in signal) { - return (...args: CommandArgs): T => { - const ret = store.set(signal, ...args); - - return ret; - }; - } - - return (value: StateArg) => { - store.set(signal, value); - }; + return useCallback( + 'write' in signal + ? (...args: CommandArgs): T => { + return store.set(signal, ...args); + } + : (value: StateArg) => { + store.set(signal, value); + }, + [store, signal], + ); }