Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | 9x 45x 45x 35x 10x 4x 6x 45x 45x 45x 45x 21x 22x 22x 45x 105x 96x 45x 29x 29x 24x 24x 45x 45x 45x 21x 29x 21x 45x 22x 22x 45x | import * as React from 'react'; import { StateGetter } from './types'; import { Store } from './Store'; import { objectIs } from './utils'; type TupleOfStateGetter = [] | [StateGetter<any>, ...StateGetter<any>[]]; type ExtractState<T> = T extends StateGetter<any>[] ? { [P in keyof T]: T[P] extends StateGetter<infer S> ? S : never } : never; type EqualityFn = (a: unknown, b: unknown) => boolean; const defaultEquality = objectIs; export function useMappedState<T extends TupleOfStateGetter, R>( stateGetters: T, mapperFn: (...args: ExtractState<T>) => R, deps?: any[] ): R; export function useMappedState<T extends TupleOfStateGetter, R>( stateGetters: T, mapperFn: (...args: ExtractState<T>) => R, equalityFn: EqualityFn, deps?: any[] ): R; export function useMappedState( stateGetters: StateGetter<any>[], mapperFn: (...args: any[]) => any, equalityFnOrDeps?: EqualityFn | unknown[], mayBeDeps: unknown[] = [] ) { const parseArgs = (): [unknown[], EqualityFn] => { if (equalityFnOrDeps === undefined) { return [[], defaultEquality]; } if (Array.isArray(equalityFnOrDeps)) { return [equalityFnOrDeps, defaultEquality]; } return [mayBeDeps, equalityFnOrDeps]; }; const [deps, equalityFn] = parseArgs(); const mapperCached = React.useCallback(mapperFn, deps); const [, forceUpdate] = React.useReducer(x => x + 1, 0); const stores = React.useMemo( () => stateGetters.map((getter: any) => { Iif (!getter._store) { throw new Error( `_store not found in getter for module "${getter._module || 'unknown'}". Make sure to load the module before using 'useState' or 'useMappedState'.` ); } return getter._store as Store; }), [] ); const getMappedState = () => { const states = stores.map(store => store.state); return mapperCached(...states); }; const getSubscribeFn = () => { const newState = getMappedState(); if (!equalityFn(newState, stateRef.current)) { stateRef.current = newState; forceUpdate({}); } }; const stateRef = React.useRef(getMappedState()); const subscribeRef = React.useRef(getSubscribeFn); // subscribe to stored immediately // React.useEffect can sometimes miss updates React.useLayoutEffect(() => { const subscriptions = stores.map(store => store.subscribe(() => subscribeRef.current()) ); return () => { subscriptions.forEach(subscription => subscription()); }; }, []); React.useMemo(() => { stateRef.current = getMappedState(); subscribeRef.current = getSubscribeFn; }, deps); return stateRef.current; } |