import { createStore } from 'zustand';
export interface BearProps {
bears: number;
}
export interface BearState extends BearProps {
addBear: () => void;
sync: (props: any) => void;
}
export type BearStore = ReturnType<typeof createBearStore>;
export const createBearStore = (initProps?: Partial<BearProps>) => {
const DEFAULT_PROPS: BearProps = {
bears: 0,
};
return createStore<BearState>()((set) => ({
...DEFAULT_PROPS,
...initProps,
addBear: () => set((state) => ({ bears: ++state.bears })),
sync: (props) => {
set(props);
},
}));
};
import React, { useRef } from 'react';
import { createContext } from 'react';
import {
BearProps,
BearState,
BearStore,
createBearStore,
} from './local-store';
export const BearContext = createContext<BearStore | null>(null);
type BearProviderProps = React.PropsWithChildren<BearProps>;
export const Syncer = (props: any) => {
const sync = useBearContext((s) => s.sync);
React.useEffect(() => {
if (props) {
sync(props);
}
}, [props]);
return <></>;
};
export function BearProvider({ children, ...props }: BearProviderProps) {
const storeRef = useRef<BearStore>();
if (!storeRef.current) {
storeRef.current = createBearStore(props);
}
return (
<BearContext.Provider value={storeRef.current}>
<Syncer {...props} />
{children}
</BearContext.Provider>
);
}
import { useContext } from 'react';
import { useStore } from 'zustand';
export function useBearContext<T>(selector: (state: BearState) => T): T {
const store = useContext(BearContext);
if (!store) throw new Error('Missing BearContext.Provider in the tree');
return useStore(store, selector);
}
import React from 'react';
import { BearProvider, useBearContext } from './provider';
const HookConsumer = () => {
const bears = useBearContext((s) => s.bears);
return <pre>{JSON.stringify(bears, null, 2)}</pre>;
};
export const Home = () => {
const [localBear, setLocalBear] = React.useState<number>(0);
return (
<BearProvider bears={localBear}>
<button
onClick={() => {
setLocalBear((prev) => {
return prev + 1;
});
}}
>
Add Bear
</button>
<HookConsumer />
</BearProvider>
);
};