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],
+ );
}