import * as React from 'react' ; import immer , { Draft } from 'immer' ; type Listener = Function ; type UpdaterFn < S > = ( prevState : S ) => S ; export interface Store < S > { get ( ) : S ; set ( nextState ) : void ; set ( updater ) : void ; on ( listener ) : ( ) => void ; off ( listener ) : void ; reset ( ) : void ; mutate ( updater ) : void ; } export function createStore < S > ( initialState ) { let listeners = [ ] ; let currentState = initialState ; return { get ( ) { return currentState ; } , set ( nextState ) { currentState = typeof nextState === 'function' ? ( nextState as UpdaterFn < S > ) ( currentState ) : nextState ; listeners . forEach ( listener => listener ( ) ) ; } , on ( listener ) { listeners . push ( listener ) ; return ( ) => this . off ( listener ) ; } , off ( listener ) { listeners = listeners . filter ( fn => fn !== listener ) ; } , reset ( ) { this . set ( initialState ) ; } , mutate ( updater ) { let currState = this . get ( ) ; let nextState = immer ( currState , updater ) ; if ( nextState !== currState ) this . set ( nextState as S ) ; } , } ; } function getStoreVersion < S > ( store ) { return store . get ( ) ; } function subscribe < S > ( store , callback ) { return store . on ( callback ) ; } const MutableSourceContext = React . createContext < Store < unknown > > ( null as any ) ; export function Provider < S > ( { children , store , } ) { const mutableSource = React . useMemo ( ( ) => { return ( React as any ) . unstable_createMutableSource ( store , getStoreVersion ) ; } , [ store ] ) ; return React . createElement ( MutableSourceContext . Provider , { value : mutableSource } , children ) ; } export function useSelector < S , V > ( selector ) { const mutableSource = React . useContext ( MutableSourceContext ) ; const getSnapshot = React . useCallback ( store => selector ( store . get ( ) ) , [ selector , ] ) ; return ( React as any ) . unstable_useMutableSource ( mutableSource , getSnapshot , subscribe ) ; }