import { useEffect , useRef , useCallback } from 'react' ; import debounce from 'lodash/debounce' ; import isEqual from 'lodash/isEqual' ; import { useSafeSetState } from '../util' ; import { FilterPayload } from '../types' ; interface UseFilterStateOptions { filterToQuery ? : ( v : string ) => FilterPayload ; permanentFilter ? : FilterPayload ; debounceTime ? : number ; } typedef UseFilterStateProps property { Object } filter property { setFilter } setFilter interface UseFilterStateProps { filter : FilterPayload ; setFilter : ( v : string ) => void ; } const defaultFilterToQuery = ( v ) => ( { q : v } ) ; example param option param { Function } option . filterToQuery param { Object } option . permanentFilter param { number } option . debounceTime returns { UseFilterStateOptions } export default ( { filterToQuery = defaultFilterToQuery , permanentFilter = { } , debounceTime = 500 , } ) : UseFilterStateProps => { const permanentFilterProp = useRef ( permanentFilter ) ; const latestValue = useRef < string > ( ) ; const [ filter , setFilterValue ] = useSafeSetState ( { ... permanentFilter , ... filterToQuery ( '' ) , } ) ; const permanentFilterSignature = JSON . stringify ( permanentFilter ) ; useEffect ( ( ) => { if ( ! isEqual ( permanentFilterProp . current , permanentFilter ) ) { permanentFilterProp . current = permanentFilter ; setFilterValue ( { ... permanentFilter , ... filterToQuery ( latestValue . current ) , } ) ; } } , [ permanentFilterSignature , permanentFilterProp , filterToQuery ] ) ; const setFilter = useCallback ( debounce ( ( value ) => { setFilterValue ( { ... permanentFilter , ... filterToQuery ( value ) , } ) ; latestValue . current = value ; } , debounceTime ) , [ permanentFilterSignature ] ) ; return { filter , setFilter , } ; } ;