5 ms·
I have actually just started a process like this in a personal react project. The project uses password auth and websockets, and I was starting to get bugs aro
by migf 3y ago
I have actually just started a process like this in a personal react project.
The project uses password auth and websockets, and I was starting to get bugs around refreshing things that I couldn't easily fix.
I had implemented this originally using a singleton pattern for an AuthService and a MessageBus for the websockets. I created those at app start and put them in a React Context.
Converting things to xstate is working great, but it's nearly a rewrite. The approach I had stashed state in a couple different places and had a bunch of callbacks passed around. Now all that state is just in the state machine's context, and what were methods turn into pure functions.
One thing that's a little non obvious is that if you have async operations (ie waiting for a new token) you probably want a state for waiting for that, where you invoke the async method followed by transitions on success and failure. The docs reflect this, but it's not narratively obvious.
Anyway, liking it so far. Changing to a state machine is going to hurt if your code already sucks.
- komali2 3y agoInteresting use case, because for a react project with lots of state management, were you not using redux? And if so, were you using Redux Toolkit? https://redux-toolkit.js.org/ https://redux-toolkit.js.org/ The last major react project I worked on I found that RTK kinda functioned as a state machine definition for the project, and let us work on requests states in our components, i.e. if loading do this, if not yet loaded do that, etc. I guess with this state machine framework you'd also be managing DOM state in one spot which could be kind of nice. In the big project we had to consider Formik managed input fields, buttons, modals, etc.
- acemarke 3y agoHi, I maintain Redux and created RTK. I'm going to do my best @davidkpiano impression and point out that "Redux, as typically used, is _half_ a state machine" [0] , in that a typical reducer responds to actions regardless of what the current state value might be, whereas a true Finite State Machine always checks the current state first before deciding if the current event is relevant. You _can_ absolutely write Redux reducers as true state machines. With `createSlice`, you'd generally need to have a field in the slice that's some kind of enum, and check that first inside of a reducer: const someSlice = createSlice({ name, initialState: {status: "x", someData}, reducers: { somethingHappened(state, action) { if(state.status === "x") { // _now_ consider if the "somethingHappened" action is relevant } } } }) Very doable, but not the most ideal syntax, since `createSlice` is focused on "here's an action / thing that happened, here's the reducer that handles that". On the flip side, you can also use XState state machines as Redux reducers. A state machine is, after all, a function that takes a current state value + some event, and returns a new state.... exactly the same as a reducer function! David and I have been saying for a while that we'd like to have a more official integration between XState and Redux. A while back, Matt Pocock put together an proof of concept for what a `createXStateSlice` might look like [1]. I actually sat down with David a couple weeks ago and we did some further design discussions about the possibility of using the `@xstate/fsm` package (a smaller version of XState's logic) as a starting point, and generating RTK actions based on that. No code yet, but it seems feasible. [0] https://dev.to/davidkpiano/redux-is-half-of-a-pattern-1-2-1hd7 https://dev.to/davidkpiano/redux-is-half-of-a-pattern-1-2-1h... [1] https://github.com/mattpocock/redux-xstate-poc https://github.com/mattpocock/redux-xstate-poc
- komali2 3y agoThat's pretty awesome news regarding your conversations. I hadn't even thought of the `reducers` slice property. I meant more all the thunky features around the `endpoints` property and the hooks that are autogenerated as a result. In our components this meant we could have for example a form that takes an api model as input and can modify that model on submit. So like, ...component boilerplate const { data, isLoading, isFetching, isError, isSuccess, } = useGetSomeDataQuery(); const [updateData, { isLoading, isUninitialized, isSuccess, isError }] = useSomeDataMutation(); And then right there is all the state we really need to worry about for a given form as we interact with the API. Though again the missing bits are the stuff managed by Formik, like changed but unsubmitted inputs and etc, but those definitions would also be up top near the RTK stuff and so at least while editing it's visually available. Like you said doesn't necessarily pass muster as an actual state machine unless you have lots of checks in your useEffects or wherever else you're reacting to state changes about the entire state of the component.