import { useReducer , useEffect } from 'react' ; import { createContext , useContextSelector , useContext } from 'use-context-selector' ; import { config , getConfigSnapshot } from './config' ; import { reducer , createActionConfigLoad } from './reducer' ; import debounce from 'lodash-es/debounce' ; import isEqual from 'react-fast-compare' ; import type { ActionMessage } from './reducer' ; import type { BuildStore , BuildStoreSnapshot } from './types' ; const STORAGE_KEY = 'lwjgl-build-config' ; export const StoreContext = createContext < BuildStore > ( config ) ; export const DispatchContext = createContext < React . Dispatch < ActionMessage > > ( ( ) => { } ) ; if ( ! FLAG_PRODUCTION ) { StoreContext . displayName = 'StoreContext' ; DispatchContext . displayName = 'DispatchContext' ; } export function useStore ( ) { return useContext ( StoreContext ) ; } export function useDispatch ( ) { return useContext ( DispatchContext ) ; } export function useSelector < T > ( selector ) { return useContextSelector ( StoreContext , selector ) ; } export let latestStore ; let prevConfig ; function saveSnapshot ( state ) { if ( state === config ) { return ; } const save = getConfigSnapshot ( state ) ; if ( save === null ) { if ( prevConfig !== null ) { prevConfig = null ; localStorage . removeItem ( STORAGE_KEY ) ; } return ; } if ( prevConfig === null || ! isEqual ( prevConfig , save ) ) { prevConfig = save ; localStorage . setItem ( STORAGE_KEY , JSON . stringify ( save ) ) ; } } const saveSnapshotDebounced = debounce ( saveSnapshot , 1000 ) ; export const Provider = ( props ) => { const [ state , dispatch ] = useReducer < React . Reducer < BuildStore , ActionMessage > > ( reducer , config ) ; useEffect ( ( ) => { const restore = localStorage . getItem ( STORAGE_KEY ) ; if ( restore !== null ) { try { prevConfig = JSON . parse ( restore ) as BuildStoreSnapshot ; dispatch ( createActionConfigLoad ( prevConfig ) ) ; } catch ( err ) { localStorage . removeItem ( STORAGE_KEY ) ; } } return ( ) => { saveSnapshotDebounced . flush ( ) ; } ; } , [ ] ) ; useEffect ( ( ) => { latestStore = state ; saveSnapshotDebounced ( state ) ; } ) ; return ( < DispatchContext . Provider value = { dispatch } > < StoreContext . Provider value = { state } > { props . children } < /StoreContext.Provider> < /DispatchContext.Provider>); } ;