Last active
July 9, 2020 16:56
-
-
Save alexreardon/cd17502b31a246caab67115d3095c28d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import React, { createContext, ReactNode, useEffect, useMemo, useRef, useState } from 'react'; | |
| import { interpret } from 'xstate'; | |
| import useRequiredContext from '../shared/use-required-context'; | |
| import { Nullable } from '../types'; | |
| import isShallowEqual from './is-shallow-equal'; | |
| import machine from './machine'; | |
| import { MachineEvents, MachineStateType, ServiceType } from './machine-types'; | |
| const ServiceContext = createContext<Nullable<ServiceType>>(null); | |
| export function WithStateMachine({ children }: { children: ReactNode }) { | |
| // A single service from a single machine | |
| const service = useMemo(() => { | |
| const result = interpret(machine); | |
| result.start(); | |
| return result; | |
| }, []); | |
| useEffect(() => { | |
| return () => { | |
| service.stop(); | |
| }; | |
| }, [service]); | |
| return <ServiceContext.Provider value={service}>{children}</ServiceContext.Provider>; | |
| } | |
| export function useSelector<State>(selector: (machineState: MachineStateType) => State) { | |
| const service = useRequiredContext(ServiceContext); | |
| const [state, setState] = useState<State>(() => { | |
| const initial = service.initialized ? service.state : service.initialState; | |
| return selector(initial); | |
| }); | |
| const currentStateRef = useRef<State>(state); | |
| useEffect(() => { | |
| const { unsubscribe } = service.subscribe((newState: MachineStateType) => { | |
| const result: State = selector(newState); | |
| const isSame: boolean = isShallowEqual(result, currentStateRef.current); | |
| if (isSame) { | |
| return; | |
| } | |
| currentStateRef.current = result; | |
| setState(result); | |
| }); | |
| return unsubscribe; | |
| }, [selector, service, setState]); | |
| return state; | |
| } | |
| export function useSend(): ServiceType['send'] { | |
| const service = useRequiredContext(ServiceContext); | |
| return service.send; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment