Skip to content

Commit

Permalink
fix: keep state in reducer (#12)
Browse files Browse the repository at this point in the history
* fix: keep state in reducer

* update CHANGELOG
  • Loading branch information
dai-shi authored Aug 25, 2024
1 parent 54183b8 commit 95540b0
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 9 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

### Changed

- fix: keep state in reducer #12

## [0.1.1] - 2024-08-19

### Changed
Expand Down
21 changes: 12 additions & 9 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useMemo, useReducer } from 'react';
import { useEffect, useReducer } from 'react';
import type { DispatchWithoutAction, Reducer } from 'react';
import type { StoreApi } from 'zustand';

Expand All @@ -8,27 +8,29 @@ export function useZustand<State, Slice>(
areEqual: (a: Slice, b: Slice) => boolean = Object.is,
) {
const state = store.getState();
const slice = useMemo(() => selector(state), [state, selector]);
const [[sliceFromReducer, storeFromReducer], rerender] = useReducer<
Reducer<readonly [Slice, StoreApi<State>], boolean | undefined>,
Reducer<
readonly [Slice, StoreApi<State>, State],
readonly [Slice, StoreApi<State>, State] | undefined
>,
undefined
>(
(prev, fromSelf?: boolean) => {
(prev, fromSelf) => {
if (fromSelf) {
return [slice, store];
return fromSelf;
}
const nextState = store.getState();
if (Object.is(state, nextState) && prev[1] === store) {
if (Object.is(prev[2], nextState) && prev[1] === store) {
return prev;
}
const nextSlice = selector(nextState);
if (areEqual(prev[0], nextSlice) && prev[1] === store) {
return prev;
}
return [nextSlice, store];
return [nextSlice, store, nextState];
},
undefined,
() => [slice, store],
() => [selector(state), store, state],
);
useEffect(() => {
const unsubscribe = store.subscribe(() =>
Expand All @@ -38,7 +40,8 @@ export function useZustand<State, Slice>(
return unsubscribe;
}, [store]);
if (storeFromReducer !== store) {
rerender(true);
const slice = selector(state);
rerender([slice, store, state]);
return slice;
}
return sliceFromReducer;
Expand Down

0 comments on commit 95540b0

Please sign in to comment.