import { useState , useEffect } from 'react' ; import { getLogger } from '../../shared/logger' ; export function useStore < T extends Store < any > > ( StoreInstance ) { const [ state , setState ] = useState ( StoreInstance . getState ( ) ) ; useEffect ( ( ) => { StoreInstance . subscribe ( setState ) ; return ( ) => StoreInstance . unsubscribe ( setState ) ; } , [ StoreInstance ] ) ; return [ state , StoreInstance . dispatch . bind ( StoreInstance ) ] ; } export interface Action { type : string ; payload ? : any ; id ? : number ; } export class Store < S > { private listeners : ( ( state : S ) => void ) [ ] = [ ] ; private reducers : ( ( action : Action , state : S ) => S ) [ ] = [ ] ; private effects : ( ( action : Action , state : S ) => void ) [ ] = [ ] ; private _log : ReturnType < typeof getLogger > ; constructor ( public state , name ? ) { if ( ! name ) name = 'Store' ; this . _log = getLogger ( 'renderer/stores/' + name ) ; } get log ( ) { return this . _log ; } getState ( ) { return this . state ; } dispatch ( action ) { this . log . debug ( 'DISPATCH of type' , action . type ) ; let state = this . state ; this . reducers . forEach ( reducer => { state = reducer ( action , state ) ; } ) ; this . effects . forEach ( effect => { effect ( action , state ) ; } ) ; if ( state !== this . state ) { this . log . debug ( `DISPATCHING of "${ action . type }" changed the state.` ) ; this . state = state ; this . listeners . forEach ( listener => listener ( this . state ) ) ; } } subscribe ( listener ) { this . listeners . push ( listener ) ; return this . unsubscribe . bind ( this , listener ) ; } unsubscribe ( listener ) { const index = this . listeners . indexOf ( listener ) ; this . listeners . splice ( index , 1 ) ; } attachEffect ( effect ) { this . effects . push ( effect ) ; } attachReducer ( reducer ) { this . reducers . push ( reducer ) ; } setState ( stateReducer , description ) { const modifiedState = stateReducer ( this . state ) ; if ( modifiedState === undefined ) return ; this . log . debug ( `${ description } changed the state` ) ; this . state = modifiedState ; this . listeners . forEach ( listener => listener ( this . state ) ) ; } }