Vuex: How about add dispatch interface on vuex getter?

I know that dispatch will bring side effects on pure function getter, but I have some thoughts and it may actually bring a more elegant way to fetch remote data.

What is the best practice on handling apis and store and access data? If A, B, C components all need to access a getter, you need to pull down data first, vuex’s asyc action is responsible for it. But how to trigger these actions? Generally we trigger it in vue created or mounted interface, or bind actions on dom events, or watch interface which watching on $route. I think these ways may call fetching actions many times and mutate state many times. Maybe computed is a nicer interface for fetching data.

There is a usage:

// A component

computed: {
  ...mapGetters([ 'books', 'booksStatus' ]),
  theBooks () { // Use this.theBooks instead the this.books in render function
    if (this.booksStatus === null) this.fetchBooks()
    return this.books
  }
},
methods: {
  ...mapActions([ 'fetchBooks' ]) // ajax request
}

//  vuex stuffs

const state = {
  books = [],
  booksStatus = null // null | 'pending' | 'success' | 'failed'
}

const actions = {
  fetchBooks: ({ commit }) => {
    // do: state.booksStatus = 'pending'
    commit('FETCHBOOKS_REQUEST')

    fetch ('url')
    // do: state.booksStatus = 'success', state.books = books
    .then(res => { commit('FETCHBOOKS_SUCCESS', res.books)})
    // do: state.booksStatus = 'failed'
    .catch(err => { commit('FETCHBOOKS_FAILURE') })
  }
}

It’s a promise like way for handing fetching data. dataStatus indicate the fetching status, computed trigger action and return state through getter. Once fetching ‘fullfilled’ (dataStatus become ‘success’), the value of getter will be updated and trigger component rerendering. Getter theBooks pull down data automatically and a not null dataStatus will block repeatedly fetching data.

A furthermore step is removing the computed bookStatus and theBook, and not import fetchBooks actions. Unless you need bookStatus for displaying some UI effect to indicate fetching process, or bind fetching actions on dom events. I can import bookStatus getter and fetchBooks actions in the specific requirement but they are totally redundant for books getter.

How to remove bookStatus and fetchBooks? Just add dispatch on getter interface. Make vuex getters receive prarams:

  • state,
  • getters,
  • rootState,
  • dispatch

We can use it as following.

const getters = {
  books: ({ state, getters, dispatch}) => {
    if (getters.booksStatus === null) dispatch('fetchBooks')
    return state.books
  }
}

books getter will automatically pull down data and always return the real time value if some components need books. And If you need bookStatus or fetchBooks in components, it is a situation that you indeed need them for your component features not just for pull down data because getter return the initial default value.

Though the design philosophy of vuex getter is that having no side effects and be pure function for tracking easy, the dispatch interface can actually bring more conveniences. If vuex no idea on this change, can anyone give some suggestions on fetching data(for global using) practices?

2 Likes

As you’ve already mentioned with bringing side effects to getters etc, this doesnt make sense in the end. Vuex is predictable and testable and built with these concepts specifically in mind.

If you’re concerned about data not being there, that is up to you on how to structure this logic, incase you dont want to run the same ajax actions over and over again. This type of thinking belongs outside within your component… or perhaps even within the action that does the ajax. If the state is already filled, just return, no need to run your ajax call, but of course your business requirements will vary for this type of work.

I also think computed properties running AJAX also an inappropriate use and brings more side effects. Logistically it doesnt make sense to do such a call within a computed property. And I cant imagine the side effects that could cause.

In some situations, developer want to bind api fetchers on dom events, now that the project imported vuex, it is certainly that call fetcher within actions for doing state mutations. In the official documents of vue, I haven’t seen any guide mentioned that computed mustn’t bring side effects (sp in the section computed vs watch), and in actually many vue projects did some non-idempotent operations in computed.

Can anyone give me some suggestions about this thoughts? I’m still expecting an universal practices on handling apis in vue development.