Best Practices: Bootstrapping Ajax data when using Vuex

I’m digging into my first large Vue + Vuex application, and naturally I need to fetch data from a backend server in order to hydrate my application’s state. Think of an account-based app that saves your customer information, orders, etc.

My question is what are the best practices for fetching data and hydrating the app’s vuex store state? I’m clear that actions should perform the async fetching, and mutations will be committed on fetch complete in those actions. Where should I be dispatching these actions?

So far, my root app component uses the created hook to dispatch each fetch (fetchUserProfile, fetchOrders, etc.). This works just fine, and my components simply re-render as data is pulled into the store.

Is this the best practice? Using the beforeCreate hook seems risky because data observation hasn’t been performed yet. Having my store perform the fetch also seems wrong, as it feels more like the responsibility of the app’s components to request data (this could make my store more reusable in other contexts when we perhaps don’t need to fetch something like orders).

Thoughts?

2 Likes

P.S. This is getting more complex as I try to create a component that displays the fetched data, but also toggles to an editing state that allows a user to modify the data.

Consider an account settings panel that displays your user data in a card. This should be rendered from the user data we bootstrap from the server, and acts more as read-only.

Now you can click an edit button that toggles the card to a form with all the user data pre-populated. This should be a mutable copy of the app state user data, so we can let the user edit it while we validate the data and so we can revert the data back if they cancel.

I’m experimenting with creating mutable clones from the vuex state, but the tricky part is where to do that. The best guess so far is a vuex store getter that returns a true clone, so that when the backend data arrives, the clone should update and pass along it’s new data.

Update

I’m having success with this setup:

  1. Pass the user data from vuex state down to user card component as prop
  2. In the data function, create a deep clone of the user with a new name so it doesn’t clash with the prop (e.g. userMutable)
  3. Define a watcher for the prop user that re-clones the data to userMutable (this is also where I assign the password field the user edited to the clone, since that field is stripped from the vuex state user by the backend, but used here temporarily to reset a user password)

I appear to be having a conversation with myself, but for posterity, I believe I’ve distilled the solution down to a mixin:

// this is a class that implements utility methods (lodash) scoped to the model
// as well as integrates ajax client for CRUD methods (axios)
import RichModel from '../core/classes/RichModel'

export default {
    // pass in the model living in the vuex store as a prop,
    // so that it has reactivity for when the store updates the model.
    // The parent will pass the updated model into the component on update
    props: {
        model: {
            type: RichModel,
            required: true,
        },
    },

    // make a mutable deep clone of the data
    // so we can edit this without affecting the store
    data() {
        return {
            modelClone: this.model.cloneDeep(),
        }
    },

    // CRITICAL: add a watcher that reclones our model when the prop is updated
    watch: {
        model(newModel) {
            // reassign to avoid mishaps with the reactivity observation
            // deep cloning is my use case—simpler objects can just be replaced with a fresh copy
            this.modelClone = Object.assign(this.modelClone.cloneDeep(), newModel.cloneDeep())
        },
    },

    // the reset method mentioned above. 
    // Helpful when enabling a user to cancel the edit
    methods: {
        resetModelClone() {
            this.modelClone = this.model.cloneDeep()
        },
    },
}

1 Like

LOL, the best conversation you will have all year @alexsasharegan.

1 Like

Thanks @alexsasharegan for documenting your thinking here, very helpful. I am starting to run into a couple issues like this myself as I am getting my feet wet with a larger vue + veux application. In the next couple days I will be using some this to guide my process. Thanks again

1 Like