Skip to content

Commit

Permalink
✨ feat: createContext support for custom defaultEqualityFn (#3)
Browse files Browse the repository at this point in the history
* 🐛 fix: custom eq method without inheritance error

* chore: update comment

* chore: update peerdep

* Revert "chore: update peerdep"

This reverts commit dfc5b3a.

* feat: plan 2

* Revert "feat: plan 2"

This reverts commit b19ab77.

* feat: createContext support for defaultEqualityFn custom
  • Loading branch information
Wxh16144 authored Jan 13, 2025
1 parent 474cb9b commit 4b71b99
Showing 1 changed file with 17 additions and 13 deletions.
30 changes: 17 additions & 13 deletions src/context.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { ReactNode } from 'react';
import { createElement, createContext as reactCreateContext, useContext, useRef } from 'react';
import type { StoreApi } from 'zustand';
import { shallow } from 'zustand/shallow';
import { useStoreWithEqualityFn } from 'zustand/traditional';

export type UseContextStore<S extends StoreApi<unknown>> = {
Expand All @@ -12,11 +13,16 @@ type ExtractState<S> = S extends { getState: () => infer T } ? T : never;

type WithoutCallSignature<T> = { [K in keyof T]: T[K] };

interface CreateContextParams {
equalityFn?: <U>(a: U, b: U) => boolean;
}

/**
* create context for individual App
* mostly use for component
*/
export const createContext = <S extends StoreApi<unknown>>() => {
export const createContext = <S extends StoreApi<unknown>>(params: CreateContextParams = {}) => {
const defaultEqualityFn = params.equalityFn || shallow;
const ZustandContext = reactCreateContext<S | undefined>(undefined);

const Provider = ({ createStore, children }: { createStore: () => S; children: ReactNode }) => {
Expand All @@ -29,29 +35,27 @@ export const createContext = <S extends StoreApi<unknown>>() => {
return createElement(ZustandContext.Provider, { value: storeRef.current }, children);
};

const useContextStore: UseContextStore<S> = <StateSlice = ExtractState<S>>(
selector?: (state: ExtractState<S>) => StateSlice,
equalityFn?: (a: StateSlice, b: StateSlice) => boolean,
) => {
const useStoreApi = () => {
const store = useContext(ZustandContext);
if (!store) {
throw new Error('Seems like you have not used zustand provider as an ancestor.');
}
return store as WithoutCallSignature<S>;
};

const useContextStore: UseContextStore<S> = <StateSlice = ExtractState<S>>(
selector?: (state: ExtractState<S>) => StateSlice,
equalityFn = defaultEqualityFn,
) => {
const store = useStoreApi();

return useStoreWithEqualityFn(
store,
selector as (state: ExtractState<S>) => StateSlice,
equalityFn,
);
};

const useStoreApi = () => {
const store = useContext(ZustandContext);
if (!store) {
throw new Error('Seems like you have not used zustand provider as an ancestor.');
}
return store as WithoutCallSignature<S>;
};

return {
Provider,
useStore: useContextStore,
Expand Down

0 comments on commit 4b71b99

Please sign in to comment.