Skip to content

Commit e58bdf2

Browse files
committed
fix(zustand): publish shared main external writes
1 parent 5f1262c commit e58bdf2

2 files changed

Lines changed: 39 additions & 3 deletions

File tree

packages/coaction-zustand/src/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,16 @@ export const bindZustand = ((initializer: StateCreator<any, [], []>) =>
3333
internal.rootState = zustandStore.getState() as object;
3434
const unsubscribe = zustandStore.subscribe(() => {
3535
if (!isCoactionUpdated) {
36-
internal.rootState = zustandStore.getState() as object;
36+
const nextState = zustandStore.getState() as object;
3737
if (coactionStore.share === 'client') {
38+
internal.rootState = nextState;
3839
throw new Error('client zustand store cannot be updated');
3940
} else if (coactionStore.share === 'main') {
4041
// emit to all clients
41-
coactionStore.setState(zustandStore.getState()!);
42+
coactionStore.setState(nextState);
4243
return;
4344
}
45+
internal.rootState = nextState;
4446
}
4547
internal.notifyStateChange();
4648
});

packages/coaction-zustand/test/index.test.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,17 @@ test('initializer get callback reads latest state', () => {
8484
expect(useStore.getState().count).toBe(2);
8585
});
8686

87-
test('worker main propagates direct zustand mutations', () => {
87+
test('worker main propagates direct zustand mutations', async () => {
8888
type Counter = {
8989
count: number;
9090
increment: () => void;
9191
};
9292
const ports = mockPorts();
9393
const serverTransport = createTransport('WebWorkerInternal', ports.main);
94+
const clientTransport = createTransport(
95+
'WebWorkerClient',
96+
ports.create() as WorkerMainTransportOptions
97+
);
9498
const counter: StateCreator<Counter, [], []> = (set) => ({
9599
count: 0,
96100
increment() {
@@ -102,8 +106,38 @@ test('worker main propagates direct zustand mutations', () => {
102106
transport: serverTransport,
103107
name: 'test-worker-main'
104108
});
109+
const serverListener = jest.fn();
110+
const signalValues: number[] = [];
111+
useServerStore.subscribe(serverListener);
112+
const stop = effect(() => {
113+
signalValues.push(useServerStore.getState().count);
114+
});
115+
const useClientStore = create(
116+
() => adapt(createWithZustand(bindZustand(counter))),
117+
{
118+
clientTransport,
119+
name: 'test-worker-main'
120+
}
121+
);
122+
await new Promise((resolve) => {
123+
clientTransport.onConnect(() => {
124+
setTimeout(resolve);
125+
});
126+
});
127+
const clientListener = jest.fn();
128+
useClientStore.subscribe(clientListener);
129+
105130
underlyingStore.setState({ count: 6 });
131+
await new Promise((resolve) => {
132+
setTimeout(resolve);
133+
});
134+
stop();
135+
106136
expect(useServerStore.getState().count).toBe(6);
137+
expect(serverListener).toHaveBeenCalledTimes(1);
138+
expect(signalValues).toEqual([0, 6]);
139+
expect(useClientStore.getState().count).toBe(6);
140+
expect(clientListener).toHaveBeenCalled();
107141
});
108142

109143
test('base direct zustand mutation syncs without forwarding', () => {

0 commit comments

Comments
 (0)