@tommostools/use-context-selector
Version:
Hook for simple context slicing in React
57 lines (54 loc) • 2.19 kB
text/typescript
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 };