#Wrapper around Xstate React Hooks

1 messages · Page 1 of 1 (latest)

smoky bloom
#

Hello everyone, I'm new to xstate and I'm trying to make a wrapper to have something reusable with React
So based on this code https://github.com/astahmer/pastable/blob/main/src/react/createContextWithHook.ts
I tried to adapt it to work with xstate hooks

import { useActor, useSelector } from '@xstate/react'
import type { ContextFrom, EventFrom, InterpreterFrom, StateFrom, StateMachine } from 'xstate'

import { createContextWithHook } from './createContextWithHooks'

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export const createContextForMachineWithHooks = <
  TMachine extends StateMachine<ContextFrom<TMachine>, StateFrom<TMachine>, EventFrom<TMachine>>
>({
  name,
}: {
  name: string
}) => {
  const {
    Consumer,
    Provider,
    hook: useAppService,
    Context,
  } = createContextWithHook<InterpreterFrom<TMachine>>(name, {
    name: name,
  })
  const useAppActor = () => {
    const machine = useAppService()
    return useActor(machine)
  }
  const useAppSend = () => {
    const machine = useAppService()
    return machine.send
  }
  const useAppSelector = <T>(selector: (state: StateFrom<TMachine>) => T) => {
    const machine = useAppService()
    return useSelector(machine, selector)
  }

  return {
    Consumer,
    Provider,
    useAppService,
    Context,
    useAppActor,
    useAppSend,
    useAppSelector,
  }
}

Then

//TODO: Wanna Cry ? 🤯
export const {
  Provider,
  useAppService,
  useAppSelector: useEditorSelector,
  useAppSend: useEditorSend,
  useAppActor: useEditorActor,
} = createContextForMachineWithHooks<typeof editorMachine>({
  name: 'editorMachineReactContext',
  machine: editorMachine,
})
export const EditorPage = (): JSX.Element => {
  const editorMachineService = useInterpret(editorMachine, {
    context: {},
  })
  return (
    <Provider value={editorMachineService}>

Everything works at runtime, but I don't have the typegen, so I don't have the typing for the events

#

Do you have any ideas on how to make this work? I don't think it's a big deal, maybe something to add in the generic? TMachine extends StateMachine<ContextFrom<TMachine>, StateFrom<TMachine>, EventFrom<TMachine>>

#

Thanks 😋

glad spire
#

In your machine definition you need to add
tsTypes: {} and it wll auto generate the typegen for that machine for you

smoky bloom
#

Hi, Yes I already use tsTypes with xstate cli, my code is a wrapper around xstate react hooks but the inference for events seems not working

glad spire
#

I type them separately like

type TRegistrationPageEvents =
  | { type: 'SET_CITIZENSHIP'; citizenship: string }
  | { type: 'SET_ELIGIBILITY'; eligibility: string }
  | { type: 'SET_ENTITLEMENT'; entitlement: string }
  | { type: 'I wish to register only' }
  | { type: 'I wish to register and enrol' }
  | { type: 'NEXT' }
  | { type: 'PREV' }
...
#

And then in the schema like

      schema: {
        context: {} as TRegistrationPageContext,
        events: {} as TRegistrationPageEvents,
        services: {} as TRegistrationPageServices,
      },
weak kraken
#

can you send a clip of TRegistrationPageServices for our reference

glad spire
#

Here you go

type TRegistrationPageServices = {
  fetchLocationDetails: {
    data: TLocation;
  };
  fetchFacilityId: {
    data: string;
  };
  fetchSexAtBirth: {
    data: TPredefinedListDataType[];
  };
  fetchPreferredLanguages: {
    data: TPredefinedListDataType[];
  };
  fetchIwis: {
    data: TPredefinedListDataType[];
  };
  fetchGenders: {
    data: TPredefinedListDataType[];
  };
  fetchEthnicities: {
    data: TPredefinedListDataType[];
  };
  fetchCountries: {
    data: TPredefinedListDataType[];
  };
  fetchAllStaticData: {
    data: any;
  };
  postEnrolmentForm: {
    data: TEnrolment;
  };
};
weak kraken
#

thankyou

smoky bloom
#

Ok thanks I will try with this pattern on the wrapper 😄