UNPKG

@tommostools/use-context-selector

Version:

Hook for simple context slicing in React

56 lines (55 loc) 1.8 kB
// src/index.ts import { useSubscriber } from "contexto"; import { useCallback, useEffect, useState } from "react"; function useContextSelector(context, rawSelector, deps) { const subscribe = useSubscriber(); const selector = useCallback( rawSelector instanceof Function ? rawSelector : (value) => value[rawSelector], // Ignore changes to rawSelector if it's a function – caller has responsibility for supplying the dependencies rawSelector instanceof Function ? deps || [] : [rawSelector] ); const subscribeWrapper = useCallback( () => { const [value, unsubscribe] = subscribe( context, (newValue) => setState((state2) => { const selection = selector(newValue); return selection !== state2.selection ? { value: newValue, selection, selector, context, unsubscribe } : state2; }) ); return { value, unsubscribe }; }, [context, selector, subscribe] ); const [state, setState] = useState(() => { const { value, unsubscribe } = subscribeWrapper(); return { value, selection: selector(value), selector, context, unsubscribe }; }); useEffect( () => { if (context !== state.context || selector !== state.selector) { let { value, unsubscribe, selection } = state; if (context !== state.context) { state.unsubscribe(); ({ value, unsubscribe } = subscribeWrapper()); } if (selector !== state.selector || value !== state.value) selection = selector(value); setState({ value, selection, selector, context, unsubscribe }); } }, [state, context, selector, subscribeWrapper] ); return state.selection; } var src_default = useContextSelector; export { src_default as default, useContextSelector };