import { useEffect } from 'react' ; import { useMemoOne } from 'use-memo-one' ; import { Observable } from '../core' ; import { useForceUpdate } from './common' ; const createCache = ( ) => Object . create ( null ) ; /**
 * Similar to `useMemos` except all memoized values are cached by the identity
 * of their `input` element (determined by the given `keyof` function).
 *
 * Each cached value is reused until its associated `input` element is removed,
 * which means `compute` is only called for new `input` elements.
 */ export function useKeyedMemos < T extends object , U > ( input , keyof , compute ) { const target = Observable . from ( input ) ; const cache = useMemoOne ( createCache , [ target , keyof , compute ] ) ; const output = useMemoOne ( ( ) => ( target ? target . get ( ) . map ( keyedCompute ( cache , keyof , compute ) ) : [ ] ) , [ cache ] ) ; const forceUpdate = useForceUpdate ( ) ; useEffect ( ( ) => { if ( target ) { compute = keyedCompute ( cache , keyof , compute ) ; let truncated = false ; const observer = target . _addObserver ( { _onChange ( change ) { const { prop } = change ; if ( prop == null ) { if ( truncated ) { truncated = false ; const { newValue , oldValue } = change ; for ( let i = newValue . length ; i < oldValue . length ; i ++ ) { delete cache [ keyof ( oldValue [ i ] ) ] ; } output . splice ( newValue . length , Infinity ) ; forceUpdate ( ) ; } } else if ( prop === 'length' ) { if ( change . newValue < change . oldValue ) { truncated = true ; } } else if ( ! change . deleted ) { const index = Number ( prop ) ; const result = compute ( change . newValue , index , target . get ( ) ) ; if ( result !== output [ index ] ) { output [ index ] = result ; forceUpdate ( ) ; } } } , } ) ; return ( ) => { target . _removeObserver ( observer ) ; } ; } } , [ output ] ) ; return output ; } function keyedCompute < T extends object , U > ( cache , keyof , compute ) { return ( value , index , array ) => { const key = keyof ( value ) ; const cached = cache [ key ] ; if ( cached ) { return cached ; } const result = compute ( value , index , array ) ; if ( result !== undefined && result !== false ) { cache [ key ] = result ; } return result ; } ; }