Reputation: 567
My current solution works: I get the data from the API. But Vue doesn't like it.
What is the proper way to use setInterval
within the Vuex store without "mutating the vuex store state outside mutation handlers"?
In Index.vue
:
mounted () {
store.dispatch('setAPIEndpoint', {
endpoint: 'chillersystem',
requestType: 'post',
payload: {},
})
},
In actions.js
:
async setAPIEndpoint ({ commit }, payload) {
commit('SET_API_ENDPOINT', payload)
}
In mutations.js
:
SET_API_ENDPOINT (state, payload) {
// Clear the previous interval to prevent a memory leak
if (state.api.interval !== null) {
state.api.interval = null
state.api.data = {}
}
// Reset the API parameters
state.api.endpoint = payload.endpoint
state.api.requestType = payload.requestType
state.api.payload = payload.payload
// Schedule repetition
state.api.interval = setInterval(() => {
if (state.api.requestType === 'post') {
axios.post(`/api/${ state.api.endpoint }`, state.api.payload)
.then((response) => {
state.api.data = response.data
})
.catch((error) => {
process.env.NODE_ENV === 'production' ? location.href = 'pages/error-500/' : console.log(error)
})
}
}, state.api.refreshTimer)
}
In state.js
const state = {
api: {
endpoint: '',
requestType: '',
payload: {},
data: {},
refreshTimer: 5000, // Milli-seconds
interval: null
}
}
Upvotes: 2
Views: 2556
Reputation: 567
This answer is based on @Abdullah Khan's. Refer to it for additional context.
Below is an implementable solution for anyone landing here from Google with a similar use case.
In your Vue component which need to update the API, call below from a method / lifecycle hook:
await this.$store.dispatch('setAPI', {
requestEndpoint: '/api/endpoint',
requestType: 'get',
requestPayload: {}
})
In actions.js
:
import axios from '../axios'
const actions = {
clearAPI ({ commit }) {
commit('CLEAR_API')
},
async setAPI ({ commit, state }, payload) {
commit('CLEAR_API')
const requestEndpoint = payload.requestEndpoint
const requestType = payload.requestType
const requestPayload = payload.requestPayload
let data = null
const getData = () => {
return new Promise((resolve, reject) => {
if (requestType === 'get') {
axios.get(requestEndpoint, requestPayload)
.then((response) => {
data = response.data
const newPayload = {
requestEndpoint,
requestType,
requestPayload,
data
}
commit('SET_API_DATA', newPayload)
resolve()
})
.catch((error) => {
process.env.NODE_ENV === 'production' ? location.href = 'pages/error-500/' : console.log(error)
reject()
})
}
})
}
await getData()
const interval = setInterval(() => { getData() }, state.api.pollTimer)
commit('SET_API_INTERVAL', interval)
}
}
In mutations.js
:
const mutations = {
CLEAR_API (state) {
// If interval exists, clear it
if (state.api.interval) {
clearInterval(state.api.interval)
}
// Clear the API parameters
state.api.requestEndpoint = null
state.api.requestType = null
state.api.requestPayload = null
state.api.data = {}
},
SET_API_DATA (state, payload) {
// Set the API parameters
state.api.requestEndpoint = payload.requestEndpoint
state.api.requestType = payload.requestType
state.api.requestPayload = payload.requestPayload
state.api.data = payload.data
},
SET_API_INTERVAL (state, interval) {
// If interval exists, clear it
if (state.api.interval) {
clearInterval(state.api.interval)
}
// Set the API Interval
state.api.interval = interval
}
}
In state.js
:
const state = {
api: {
requestEndpoint: null,
requestType: null,
requestPayload: null,
data: {},
interval: null,
pollTimer: 5000 // Milli-seconds
},
}
Upvotes: 0
Reputation: 550
Mutations need to run Synchronous
Do your async work in action rather than mutation
Not the best implementation, but you will get an idea how to approach it from the code below.
//mutations.js
SET_API_ENDPOINT(state, payload) {
// Clear the previous interval to prevent a memory leak
if (state.api.interval !== null) {
state.api.interval = null
state.api.data = {}
}
// Reset the API parameters
state.api.endpoint = payload.endpoint
state.api.requestType = payload.requestType
state.api.payload = payload.payload
state.api.interval = payload.interval
state.api.data = payload.data
}
//actions.js:
async setAPIEndpoint({ commit, state }, payload) {
const endpoint = payload.endpoint;
const requestType = payload.requestType;
const payload = payload.payload;
let data = null;
let interval = null;
const getData = () => {
return new Promise((resolve, reject) => {
interval = setInterval(() => {
if (requestType === 'post') {
axios.post(`/api/${endpoint}`, payload)
.then((response) => {
data = response.data;
resolve();
})
.catch((error) => {
process.env.NODE_ENV === 'production' ? location.href = 'pages/error-500/' : console.log(error)
reject();
})
}
}
, state.api.refreshTimer);
})
};
await getData();
const newPayload = {
...payload,
data,
interval
}
commit('SET_API_ENDPOINT', newPayload)
}
Upvotes: 2