0

Within a records module, there is an action, getRecords to retrieve all records from the API at /records, which commits the setRecords mutation which sets the state for records. A getter for records also exists.

Within the records vue, the created method calls the getRecords action, and the getter for records is passed to the datatable for display.

Until now everything works, however when navigating on and off the records vue, the API is called each time.

How is the properly handled? Does a best practice exist? I can move the action call to a higher level, but this generates an API that may not be required id the user never visits the records vue.

records module

const getters = {
    allRecords: state => state.records
}

const state = {
    records: []
}

const actions = {
    async getRecords({commit}){
        console.log('getting records...');
        const response = await axios.get('/api/records')
        commit('setRecords', response.data)
    },
    async addRecord({ commit }, user) {
        console.log("user :" + JSON.stringify(user))
        const response = await axios.post('/api/records', user)
            .catch(err => console.log(err))
        commit('addRecord', response.data)
    }
}

const mutations = {
    setRecords: (state, records) => (state.records = records),
    addRecord: (state, user) => ([...state.records, user])
}

export default {
    state,
    getters,
    actions,
    mutations
}
1
  • 1
    it depends on how ofter your record in backend changes and how important that user needs the most updated record. If it changes frequently, then it's ok to recall it again every time record.vue created to make user get the most updated one Commented May 21, 2020 at 17:34

2 Answers 2

3

I have handled this in various different ways in the past.

If you do not care if the data you are serving might be old, you can simply detect if you already have some items in your array:

const actions = {
    async getRecords({ commit, getters }){
        if (getters.allRecords.length > 0) {
            // Don't bother retrieving them anymore
            return;
        }
        console.log('getting records...');
        const response = await axios.get('/api/records')
        commit('setRecords', response.data)
    },
    async addRecord({ commit }, user) {
        console.log("user :" + JSON.stringify(user))
        const response = await axios.post('/api/records', user)
            .catch(err => console.log(err))
        commit('addRecord', response.data)
    }
}

If you do want to have the updated values in your database, you can consider changing your api to only return changed records after a certain timestamp. For this we need the following:

  • We need to store the timestamp of our last update. The first time we would retrieve everything, and on subsequent requests we would send the timestamp.
  • A way to identify which records to update in the local state, and which records to delete or add. Having something like an id on your records might be helpful.

Let's assume that instead of returning a flat array of your records, the api returns a response in the format

{
    records: [ ... ],
    removedRecords: [ ... ],
    timestamp: 123456789
}

You would change your state to

const state = {
    records: [],
    recordUpdateTimestamp: null
}

Your action would then look something like this:

async getRecords({ commit, state }){
    const config = {};
    if (state.recordUpdateTimestamp) {
        config.params = {
            timestamp: state.recordUpdateTimestamp
        };
    }

    console.log('getting records...');
    const { data }= await axios.get('/api/records', config)

    commit('setRecords', data.records);
    commit('removeRecords', data.removedRecords);
    commit('setRecordUpdateTimestamp', data.timestamp);
},

I will leave writing the mutations to you.

This would obviously need work in the backend to determine which records to send back, but may have the advantage of cutting down both the amount of returned data and the time processing that data a lot.

Sign up to request clarification or add additional context in comments.

Comments

1

FYI you don't need a shallow getter like the one you have. Meaning that a getter that doesn't compute your state has no value might as well use the state itself.

About the practice, it really depends on how important it is to you that "records" has always the freshest data. If you don't need it to be always fetched, you can have a "initRecords" action to run on your "App.vue" on created hook that you can use to initialize your records. If you need always fresh data, what you have is good enough.

2 Comments

The use of the getter was something else I'd also questioned. Is there any preference as to access the records state directly with the prop, or via a mapState?
Personally I use the mappers when I use namespace modules. If I just have 1 module it might look a bit unnecessary. For accessing state properties, if you want them as you typed them, getters are not necessary. Getters are good when you need to computed them (filter or stuff like that)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.