Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make "creating" and "using" a machine seperate #79

Open
devanshj opened this issue Sep 28, 2021 · 5 comments
Open

Make "creating" and "using" a machine seperate #79

devanshj opened this issue Sep 28, 2021 · 5 comments

Comments

@devanshj
Copy link
Contributor

The fact that useMachine “creates” the machine means that we can only create a machine inside an component. This problematic because...

  1. You can't define a mahine outside the component (eg)
  2. You can't get the type of the (created) machine outside the component (which is required for context, eg)

createDefinition solves 1 but doesn't solve 2 so we need something like xstate ie let m = createMachine(d); then later in component useMachine(m). We could add an overload to do useMachine(d) which saves users from writing useMachine(createMachine(d))

@devanshj
Copy link
Contributor Author

devanshj commented Sep 28, 2021

And also that means that users would "need" the second argument of useMachine too for changing things inside the component etc. – which I'm super strongly against – there's no point of reinventing functions people can just const createFooMachine = (foo: Foo) => createMachine(...). Not to mention the "named delegations" ie writing "foo" in xstate are problematic for typing because we don't know their types, here we know the type it's Foo so for us it's as if the user is writing the implementation there.

@devanshj devanshj changed the title Making "creating" and "using" a machine seperate Make "creating" and "using" a machine seperate Sep 28, 2021
@cassiozen
Copy link
Owner

I love the idea but I don't think this is super-priority given that most use cases for this library (so far) are for small, in-component state machines.

@devanshj
Copy link
Contributor Author

devanshj commented Oct 6, 2021

Yeah I wouldn't call it "super priority" but it sure makes it impossible for it to be able to use it with React's context as the type isn't available outside the component (and you create the context via React.createContext() outside the component)

@devanshj
Copy link
Contributor Author

devanshj commented Jan 15, 2022

Just putting this out because I had an idea long ago how to implement this without moving away from React or changing the implementation. It's something like this...

const createMachine = (definition) => () => {
  // same implementation
}

const useMachine = (definitionOrHook) => {
  if (typeof definitionOrHook === "function") {
    return definitionOrHook()
  }
  return createMachine(definitionOrHook)()
}

Now the machine (or more precisely the hook to use it) can be created outside the component and hence we can get its type for context too...

const useMyMachine = createMachine(...)
type MyMachine = ReturnType<typeof useMyMachine>

const MyMachineContext = React.createContext<MyMachine>()
const SomeComponent = () => {
  let machine = useMyMachine()

  return <MyMachineContext.Provider value={machine}>
    {/* ... */}
  </MyMachineContext.Provider>
}

@erickreutz
Copy link

Would love to see this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants