DEV Community

Replacing Vuex with XState

Felix Guerin on January 27, 2020

I have been learning XState and state machines these past few months and I absolutely love it. I decided to build an app using Vue and XState. I wa...
Collapse
 
danroc profile image
Daniel da Rocha

Thanks for this Felix. I went on a similar path to you: after getting excited about all the possibilities of xstate, I started using it with Vuex as written by Parker. But I also felt things were still a bit messy and verbose, while some of the guides on xstate's docs show a much nicer implementation.

I was messing around with Nuxt plugins in my case and will give your approach a try. xstate shows so much potential and I can't wait until Vue3 comes out and we can use @xstate/vue with it!

Collapse
 
felix profile image
Felix Guerin

Yes! Vue 3 will definitely make things easier. What Nuxt plugins did you try?

Collapse
 
danroc profile image
Daniel da Rocha

I was actually trying to use apollo to fetch data in my machines and for that I needed to reference the app somehow. So I figured I'd do it within a plugin file, so that I could access app:

// fetchMachine plugin
const fetchMachine = (app) => {
  return Machine({
      // ...
  })
}

export default ({ app }, inject) => {
  inject('fetchMachine', fetchMachine(app))
}
// my-component.vue
<script>
import { interpret } from 'xstate'
export default {
  data() {
    return {
      fetchService: interpret(this.$fetchMachine),
      current: this.$fetchMachine.initialState
    }
  },
  // ...
  created() {
    this.fetchService.onTransition((state) => (this.current = state)).start()
  },
  methods: {
    send(event) {
      this.fetchService.send(event)
    },
    matches(value) {
      return this.current.matches(value)
    }
  }
}

The component part above is taken from the xstate docs, the Vue implementation of their reddit API machine.

But this is very specific to one machine, and that's why I like your method because I can create machines on the fly as needed...

Thread Thread
 
felix profile image
Felix Guerin

I hadn't seen that. I'll definitely look at it. Making the machines available throughout the whole app as plugins is a really good idea. No need to import it every time.

Thread Thread
 
felix profile image
Felix Guerin

Hey Daniel, I just published a Vue plugin to facilitate the setup outlined in the post. The link is in the edit at the end if you're interested!

Thread Thread
 
danroc profile image
Daniel da Rocha

that's really cool Felix! It makes life easier and hopefully inspires othe people to try xstate and fsm in their projects!

Collapse
 
danroc profile image
Daniel da Rocha

One general question:

How do you deal with notifications? Let's say you have a fetch action which then transitions to either a 'sucess' or a 'failed' state. As in the docs, if you are using invoke, you could do something like:

      onError: {
          target: 'failure',
          actions: assign({
            errorMessage: (context, event) => {
              // event is:
              // { type: 'error.execution', data: 'No query specified' }
              return event.data;
            }
          })
        },

Would you then have a watcher on your frontend checking the value of errorMessage, or would you just watch for the 'failure' state and react accordingly?

Or something else completely?

Collapse
 
felix profile image
Felix Guerin • Edited

I guess both approaches are valid.

In the app I mention in the post I just assign the error to a context property. The component then accesses it via a computed property and an error message appears when there is a value.

You could also conditionally show the error message depending on the machine's state (success, error, etc.), which is what I did initially. In my case though, the error state was identical to the idle state, just with an error message shown. I didn't see a reason to have an error state then.

I'm still unsure if the approach I took is valid in the world of statecharts but it works!

Collapse
 
mimischi profile image
Michael Gecht

Thanks for the post Felix! I was planning to integrate xstate into my App, following this recent post: dev.to/davidkpiano/no-disabling-a-...

I am quite happy with Vuex and would like to integrate xstate to follow Davids advice on using FSM to handle the UI state in a sane way. Do you think it is reasonable to use your approach to FSM in combination with Vuex? I was thinking of triggering already available Vuex actions from the FSM actions.

Collapse
 
felix profile image
Felix Guerin

Sure, I don't see why you couldn't do that. I also like Vuex a lot, but the goal for me was to not have 2 libraries for managing state in an app and reduce my bundle size as much as possible.

I fail to see how it would be useful to have your actions in a Vuex store instead of your machine config though.

Collapse
 
mimischi profile image
Michael Gecht • Edited

I fail to see how it would be useful to have your actions in a Vuex store instead of your machine config though.

It's just inertia. I currently use Vuex actions as a central place for API calls. Putting the actions into FSM would lead to some refactoring -- which is surely doable -- but I'd rather stick with the my approach if possible.

Thread Thread
 
felix profile image
Felix Guerin

Ok I see. I think you could just import your store in your fsm file and dispatch the actions from your machine.