Dependencies on useMachine #1751
-
I have a TypeScript React app that has a set of state machines that need to be re-initialized when their components' props change. E.g: const SomeComponent:FC<{somethingDynamic:string}> = ({somethingDynamic}) => {
// createMachine is a function that creates a Machine with a dynamic context
const [state, send] = useMachine(createMachine(somethingDynamic));
// How do I have useMachine recreate the machine when the props change and ONLY when the props change?
// ...
} Normally I would do this using a dependency array but |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
This isn't an easy question to answer. Right now, it's expected that the machine is static - it should be the same for the lifetime of the component. It's like the component's "brain"; it should be deterministic logic that handles all possible states. Analogy: you have a single brain that handles your behavior when you're awake and when you're asleep; you don't swap an "asleep brain" for an "awake brain". Now, if On the other hand, if the current state were thrown away and a new initial state took its place with the changed machine, then that's effectively the same as completely swapping out the component. And you can do that already. What you probably want is for your current machine to be aware of external changes. And the way this happens, with state machines and the actor model, is through events. One way to achieve this is through useEffect(() => {
send({ type: 'UPDATED', value: someDynamicValue });
}, [someDynamicValue]); That way you don't have to completely change your machine. You might also want the dynamic value for actions. You can use refs for this: const dynamicRef = useRef(somethingDynamic);
useEffect(() => {
dynamicRef.current = somethingDynamic
}, [somethingDynamic]);
const [state, send] = useMachine(createMachine(someMachine), {
actions: {
doSomethingDynamic: () => { dynamicRef.current.doSomething() }
}
}); Overall, it might be helpful to see an example of what you're trying to do, because changing machines in-flight is probably the wrong solution. |
Beta Was this translation helpful? Give feedback.
-
Thanks for the thorough response. For additional context here's the concrete situation I'm working with:
I'm implementing this with:
const Scenario:FC<{data:ScenarioData> = ({data})=>{
const [loginState] = useLoginContext();
const userName = loginState.context.userName;
const [localState, send] = useMachine(createMachine(userName));
// stuff....
return <Button onClick={()=>{send("CREATE")}}>Create</Button>
} Your Thanks so much for the help in thinking this through. The central insight that I was forgetting was: Do not directly muck with a machine's context. Context mutations should happen through events and not with aforementioned mucking. P.S. - @Andarist Thanks for the |
Beta Was this translation helpful? Give feedback.
This isn't an easy question to answer. Right now, it's expected that the machine is static - it should be the same for the lifetime of the component. It's like the component's "brain"; it should be deterministic logic that handles all possible states.
Analogy: you have a single brain that handles your behavior when you're awake and when you're asleep; you don't swap an "asleep brain" for an "awake brain".
Now, if
useMachine
were to allow dynamic machines, what should be the expected behavior of a machine changing in-flight? If it tries to keep the current state as the machine changes, then that state may be an impossible state for the new machine, and be completely incompatible with it.O…