-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
How should a machine interact with websocket? #549
Comments
IMHO 3rd option is the best here. If the code for handling a socket gets complicated you could split things further and extract this to a machine which would be able to handle different types of messages based on socket's connection states etc. |
Thanks for replying @Andarist. I've tried implementing a machine similar to my example in option 3 and I ran into an issue. It appears xstate doesn't simply update the context object when you modify the context with Demo:
I expected Is there some way the callback service can access the current context when it receives an event via |
Think of a context as of redux state - it's immutable value, so whenever you update it with assign it creates a "copy" of the previous one, with changes applied ofc. This isn't enforced for nested values, you can mutate smth and it might stay unnoticed but I would encourage you to never mutate it. Immutable data is easier to reason about. So actually what is given to your invoked callback service is a context snapshot - so you only have data from that point in time (invocation time). To handle this here you can use expression as your event like this (link): send(
ctx => ({
type: "EMIT_JOIN_GAME",
playerName: ctx.playerName
}),
{ to: "socket" }
) Or you can use similarly event's payload because it carries that name - so maybe you don't even need to store playerName in the context in this case? it depends on your other needs though (link): send(
(ctx, ev) => ({
type: "EMIT_JOIN_GAME",
playerName: ev.playerName
}),
{ to: "socket" }
) |
Ah, I didn't realize you could pass a function to the send action creator to access the context. That's great. Thank you so much. |
I couldn't find it in the docs either - had to find it in the source code. This is something you could mention in #552 |
Looks like it is mentioned in the docs and an example is given: https://xstate.js.org/docs/guides/actions.html#send-action |
Oh, I had to miss it while scanning the docs quickly. All good then 👌 |
Bug or feature request?
Question
Description:
Apologies for the open-endedness of this question. Hopefully if there are other people wondering about this they can find this issue and gain some insight.
I'm working on a real-time multiplayer game that interacts with the server via a websocket connection (socket.io). My problem is I'm not really sure how best to make xstate and websockets work together. I've tried several approaches but none seem right.
How does the machine maintain the handle to the socket? How does the machine emit to the socket?
How should the machine subscribe to receive messages from the socket?
Approaches I've considered:
Problem: machine won't be able to access socket in actions if a side effect needs to emit to the socket.
execute: false
on my interpreter and iterate over the actions in an onTransition handler. Also have socket's event handler outside the machine which can.send
to the interpreter when the socket receives an event.Problem: too much is handled outside of machine.
callback
to send events to the machine and onEvent to receive messages that the socket should emit. Example:Problems: Seems weird to have a service at the top level of the app? Not sure how this will scale in terms of complexity in a real-world application that might have to send/receive many different types of messages.
Seems like #3 is the best approach but can't find any literature confirming/rejecting this. Any help/examples on this would be greatly appreciated.
The text was updated successfully, but these errors were encountered: