menu

Statecharts

Statecharts are a precise, visual way of modeling the behaviour of complex reactive systems. They describe how things work, and can help you get your code doing exactly what you want.

Channels
Team
Posts
Chat
Members
Info
Show previous messages

August 18, 2020 at 12:24am
notEnoughCookies: {
on: {
EAT: { target: 'checkCookies', actions: 'eatCookie' }
}
},
checkCookie: {
always: [
{ target: 'enoughCookies', cond: 'hasEnoughCookies' },
{ target: 'notEnoughCookies' }
]
},
enoughCookies: { type: 'final' }
I guess? seems a little verbose.
Edited
  • reply
  • like

August 18, 2020 at 1:15pm
It's verbose on purpose. There are two "states" in reality: the state where you executed the action, and the state where you are checking which state you should transition to based on that executed-action state.
  • reply
  • like
You can always make it less verbose by creating helper functions, since it's just a plain JS object. Nothing special there.
  • reply
  • like

August 20, 2020 at 8:49pm
So I have what I assume is a very typical use case, I have a modal flow where the user can choose to login, signup or click "forgot password". I model this as a statechart with two nested charts, one about the account creation process and another about the reset password flow (logging in is just part of the main chart)
  • reply
  • like
Since the account creation state is nested, I thought I would store context data in there (i.e. your personal data or whatever), however I can't seem to do that. It appears I am forced to have that context in the parent machine
  • reply
  • like
so the parent machine just has an initial state and can go to an "account_creation" state, which is the subchart. Inside the account_creation subchart, you can go back to the parent's "initial" state if you are in the account creation screen, but if you get past it, you can't go back anymore.
  • reply
  • like
const creation = {
initial: 'account_data',
context: {
// I want to read this
name: 'test',
some_data: 123
},
states: {
account_data: {
on: {
BACK: '#acct.initial',
NEXT: 'personal_data'
},
},
personal_data: {
on: {
NEXT: 'address'
}
},
address: {
on: {
BACK: 'personal_data',
NEXT: 'payment_data'
}
},
payment_data: {
on: {
BACK: 'address'
},
},
}
}
const machine = Machine({
id: 'acct',
initial: 'initial',
context: {
foo: 0
},
states: {
initial: {
on: {
CREATE: 'creation'
}
},
creation: {
on: {
NEXT: 'finish'
},
...creation
},
finish: {
type: "final"
}
}
});
  • reply
  • like
How can I get access to the child state? Do I have to pollute the main machine with that somewhat irrelevant state? Should I create separate machines (but then how do I go back)?
  • reply
  • like
or do I simply not use context at all, and instead use the local state of my component (I'm using react)
  • reply
  • like

October 16, 2020 at 10:51am
I was not able to understand how I can update context data by using external objects. Could some one please provide an example. I'm new to both React and xstate. I was not able to understand how to update the context
  • reply
  • like
Got it. We can update the data from the event...Thanks.
  • reply
  • like

October 27, 2020 at 10:19am
Hello everyone, I want to fetch data then update context every n seconds. But the code below doesn't work, any tips? thanks
activities: {
queryRoundStatus: (context) => {
const timer = setInterval(() => {
logger.log(`queryRoundStatus, inteval: ${HEART_BEAT_INTERVAL}`)
API.queryRoundStatus(context.gameId)
.then(data => assign({ ...data }))
}, HEART_BEAT_INTERVAL);
return () => clearInterval(timer)
},
},
  • reply
  • like
I think you would need to separate getting the data & saving the data to context. You could use a callback, then, when the callback fires, have a seperate action to save the response data to state. Here is an example of a callback that might help - https://bradwoods.io/guides/xstate/invoke-callback
  • reply
  • like
thanks, it works well.
  • reply
  • like
so I can only update context with actions, is that true?
  • reply
  • like
(simon-lu) ... more precisely, I believe I remember reading somewhere in the docs that the only way to update context is using actions.assign. The only other way I can think of is by "extending" an existing machine using withContext. I find that particularly useful when spawning child machines.
Edited
  • reply
  • like
(simon-lu) Try this:
invoke: {
src: () => (sendBack) => {
const interval = setInterval(() => sendBack({ type: 'HEARTBEAT' }), 1000)
return () => clearInterval(interval)
}
},
on: {
HEARTBEAT: { /* ... do whatever ... */}
}
  • reply
  • like
Hey there! Is there no way to get useMachine in vue2?
  • reply
  • like
I mean I can write my own implementation of it, but was just wondering if there isn't an official vue2 package for it
  • reply
  • like

October 28, 2020 at 2:42pm
That's currently in the works. Have you tried the way referenced in the docs?
  • reply
  • like
I'm not sure what way that would be? :)
  • reply
  • like
that's what I'm using, but that doesn't provide an interface to override things like services on a per-case basis?
  • reply
  • like

November 6, 2020 at 4:01pm
Would anyone have a good example of how to connect graphQL subscriptions to a state machine? Currently I'm subscribing in a Vue component and sending the result to the state machine to store in its context, but ideally I would want any data fetching/subscribing to be done in the machine instead, so my component can just be an expression of the context/state
  • reply
  • like

November 9, 2020 at 11:23pm
Using Typescript... if I spawn another machine as an actor and save the ref in context, how should I type it?
I have ServerMachine which spawns instances of SocketMachine and saves them in a sockets array in the context - but what should the type of the array be?
  • reply
  • like
Show more messages