Skip to content

Instantly share code, notes, and snippets.

@alexreardon
Last active July 9, 2020 16:56
Show Gist options
  • Select an option

  • Save alexreardon/cd17502b31a246caab67115d3095c28d to your computer and use it in GitHub Desktop.

Select an option

Save alexreardon/cd17502b31a246caab67115d3095c28d to your computer and use it in GitHub Desktop.
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