UNPKG

@tommostools/use-context-selector

Version:

Hook for simple context slicing in React

57 lines (54 loc) 2.19 kB
import { SubscriptionContext } from 'contexto'; /** * Extract a value from a context's latest value. * * @param context Contexto context object (returned from `createContext` / `createCompatibleContext`) * @param selector A field in the context value, or a function to derive a value from the context value * * `useContextSelector` is more stable than `useContext` – changes to the context value will only cause * the calling component to re-render if the _extracted value_ changes. * * useContext(MyContext).field // calling component is re-rendered every time MyContext changes * useContextSelector(MyContext, "field") // calling component re-rendered only when .field changes * * Example: * * const MyContext = createContext({ quickTick: 0, slowTick: 0 }); * * function useTicker(periodMs, delayMs=0) { * const [tick, setTick] = useState(0); * useEffect(() => { * setTimeout(() => * setInterval(() => setTick(t => t + 1), periodMs), * delayMs * ); * }, []); * return tick; * } * * const Provider = ({ children }) => { * const quickTick = useTicker(100); * const slowTick = useTicker(1000, 50); * return <MyContext.Provider value={{ quickTick, slowTick }} children={children} /> * } * * const SlowConsumer = () => { * // Will render only once a second * const tick = useContextSelector(MyContext, "slowTick"); * return <>{tick}</> * } * const QuickConsumer = () => { * // Will render 10 times a second (not 11) * const tick = useContextSelector(MyContext, "quickTick"); * return <>{tick}</> * } * * const App = () => * <Provider> * <SlowConsumer/> * <QuickConsumer/> * </Provider> */ declare function useContextSelector<TInput, TOutput>(context: SubscriptionContext<TInput>, selector: (value: TInput) => TOutput, deps?: unknown[]): TOutput; declare function useContextSelector<TInput, TKey extends keyof TInput>(context: SubscriptionContext<TInput>, selector: TKey): TInput[TKey]; export { useContextSelector as default, useContextSelector };