import { useState , useEffect } from 'react' ; type Listener < T > = ( prevState : T , nextState : T ) => void ; export class Model < State extends object = { } > { state : Readonly < State > ; _prevState : Readonly < State > ; _listeners : Listener < State > [ ] = [ ] ; _subscribe ( fn ) { this . _listeners . push ( fn ) ; } _unsubscribe ( fn ) { const listeners = this . _listeners ; listeners . splice ( listeners . indexOf ( fn ) , 1 ) ; } param state_or_updater setState < K extends keyof State > ( updater ) { let nextState ; if ( typeof updater === 'function' ) { nextState = ( updater as Function ) ( this . state ) ; } else { nextState = updater ; } if ( nextState == null ) { return ; } this . _prevState = this . state ; this . state = Object . assign ( { } , this . state , nextState ) ; this . _listeners . forEach ( listener => { listener ( this . _prevState , this . state ) ; } ) ; } } param model param props export default function useModel < S extends object , K extends keyof S > ( model , props ) ; param model param shouldUpdate export default function useModel < S extends object > ( model , shouldUpdate ? ) ; export default function useModel < S extends object , K extends keyof S > ( model , comparator ? ) { const setUpdateTime = useState ( 0 ) [ 1 ] ; useEffect ( ( ) => { const shouldUpdateFunc = ( prevState , nextState ) => { if ( comparator === undefined ) { return true ; } if ( typeof comparator === 'function' ) { return comparator ( prevState , nextState ) ; } for ( let i = 0 ; i < comparator . length ; i ++ ) { const prop = comparator [ i ] ; if ( prevState [ prop ] !== nextState [ prop ] ) { return true ; } } return false ; } ; const listener = ( prevState , nextState ) => { if ( shouldUpdateFunc ( prevState , nextState ) ) { setUpdateTime ( prev => prev + 1 ) ; } } ; model . _subscribe ( listener ) ; return ( ) => { model . _unsubscribe ( listener ) ; } ; } , [ model , comparator ] ) ; return model . state ; }