I am loading a csv file in a webworker and then push chunks of around 600 elements to the state in a loop:
mutations: {
LOAD_ITEMS: (state, { items }) => {
items.forEach(item => {
Vue.set(state.items, item.id, item)
state.lists.all.push(item.id)
state.lists.active.push(item.id)
})
}
}
The timeline shows, that adding stuff to the state is blocking the UI. So do I have to manage the state mutations in terms of performance also on my own ?
Or is the vuex / vue state not meant for datasets of around 1000-7000 objects ?
Related
I need to fetch continuously updating API endpoint data for several components on my NUXT site, 2 of which are visible simultaneously at any given moment. I wonder what is the best practice to poll the same endpoint for several different components visible at the same time?
Currently, I am using VUEX to send the API data to my components and then using setInterval with a refresh function to update the data in each component. This is clearly a clumsy solution (I am a beginner). I was thinking about polling the API directly in VUEX but I understand this is not advisable either.
This is my current (clumsy) solution:
VUEX:
// STATE - Initial values
export const state = () => ({
content: {}
});
// ACTIONS
export const actions = {
async nuxtServerInit ({ commit }) {
const response = await this.$axios.$get('https://public.radio.net/stations/see15310/status');
commit('setContent', response)
}
}
// MUTATIONS
export const mutations = {
setContent(state, content) {
state.content = content;
}
}
And in each component:
computed: {
content () {
return this.$store.state.content
},
methods: {
refresh() {
this.$nuxt.refresh()
}
},
mounted() {
window.setInterval(() => {
this.refresh();
}, 5000);
I think, it's a normal solution to do the polling in vuex. Vuex is your application state and the one source of truth for all dependant components. And if you need to update some similar state for different components - it's a rational solution to do it in vuex action.
Another solution could be the event bus. First article about it from google
Also, I don't recommend use SetInterval for polling. Because it's don't wait of async operation ending. This fact could shoot you in the foot, if a client has network delay or another glitch. I used SetTimeout for this purpose.
async function getActualData() {
// get data from REST API
}
async function doPolling() {
const newData = await getActualData() // waiting of finish of async function
// update vuex state or send update event to event bus
setTimeout(doPolling, 5000)
}
doPolling()
If my answer missed into your question, then give me more details please. What is the problem you want to solve? And what disadvantages do you see in your(by your words ;) ) "clumsy" solution?
I am confused at why actions in Vuex can't just be handled within a component.
Assuming I have a basic store:
store.js
const initialState = () => ({
overlayText: ''
})
const mutations = {
setOverlayText: (state, payload) => {
state.overlayText = payload;
},
}
const actions = {
clearOverlay: (context, data) => {
return axios.get(data.url).then((response) => {
context.commit('setOverlayText', response);
});
},
}
If I want to make an API call and change data based off it like below using a Vuex Action:
Option 1
<button #click="dispatchClearOverlay">Get Data</button>
methods: {
clearOverlay() {
this.$store.dispatch('clearOverlay', {
url: '/api/clear-overlay',
})
}
}
what is the difference of just doing it within the component like this?
Option 2
<button #click="clearOverlay">Get Data</button>
methods: {
clearOverlay() {
axios.get('api/clear-overlay')
.then(resp => {
this.$store.commit('setOverlayText', response);
})
}
}
The examples you gave are slightly different in that in Option 1, the only possible value that will get stored in state.overlayText is the response from /api/clear-overlay. But in Option 2, you could pass any arbitrary text when you commit the mutation and that value would be stored in state.overlayText.
More generally, there are some important differences. Mutations have to be synchronous and Actions can be asynchronous. You can also fire multiple mutations by dispatching a single action (imagine if you frequently needed to call the same three mutations). These two features can help keep your components nice and lean, while centralizing more of the Store logic.
The Dispatching Actions section of the Actions docs helps illustrate these points.
I have an array. I take data for it via rest api. I can call a mutation getData() from any component, but I need it to be automatically called when an object Vuex.Store is created, can I do this?
export default new Vuex.Store({
state: {
myArray: [],
},
mutations: {
getData() {
//get data from remote API and pass to myArray
axios.post('').then(response => {
this.myArray = response.data;
};
}
}
})
First things first: Mutations are synchronous pure functions. This means that your mutations should not have side-effects, and at the end of your mutation the state of your store should be updated to the new state. Axios uses promises and is thus asynchronous. You should do this in an action!
As for automatically executing a data fetch, you can either do this in the file where you define your store, or in your Vue entry point (e.g. App.vue) in a lifecycle hook. Keep in mind though that your axios call is asynchronous, which means that your app will load while data is loading in the background. You have to handle this case somehow.
// store.js
import Vue from 'vue';
import Vuex from 'vuex';
const store = new Vuex.Store({
state: {
myArray: [],
},
mutations: {
setMyArray(state, payload) {
Vue.set(state, 'myArray', payload);
},
},
actions: {
fetchData({ commit }) {
axios.post('').then(response => {
commit('setMyArray', response.data);
};
}
}
});
// Setup
Vue.use(Vuex);
// Now that we have a store, we can literally just call actions like we normally would within Vue
store.dispatch('fetchData');
// Keep in mind that action is not blocking execution. Execution will continue while data is fetching in the background
I am working on vuex app, on my other page i am committing changes to state its working, but here on this specific page i am getting some data from api and storing it in store but it get stuck in mutation, I am getting all data in mutation payload but its not effecting the changes, Please check the screenshot and code,
I can not create fiddle cuz it works there
Getting Items
async getItems () {
await this.$axios.get(`/api/projects/w/latest/all`)
.then(response => {
this.$store.commit('project/UPDATE_PROJECTS', response.data.items)
});
}
Action
updateProjectsAction (context, projects) {
context.commit('UPDATE_PROJECTS', projects)
},
Mutation
UPDATE_PROJECTS (state, payload ) {
state.projects = payload
}
State
projects: {},
Response
When i click load state or manually commit these changes it gives me this error.
In getting items
this.$store.commit('project/UPDATE_PROJECTS', response.data.items)
you should change it to
this.$store.dispatch('project/updateProjectsAction', response.data.items)
In Action you should change
updateProjectsAction ({commit}, projects) {
commit('UPDATE_PROJECTS', projects)},
And last thing, you should have getters for getting data from vuex
getters:{
getProjects: state =>{
return state.project
}
}
In .vue
import 'mapGetters' from 'vuex'
export default {
computed:{
...mapGetters({
projects: project/getProjects
})
}
}
getters and computed will helps your vue app reactive
I am modifying hacker-news example and I added notifications component (If fetching external data goes wrong: save notification with error in vuex, after user reads it and clicks X remove it from vuex state). Looks like this:
[NOTIFY] (state, message) {
state.data.push(message)
},
[READ_NOTIFICATION] (state, index) {
state.data.splice(index, 1)
}
Problem: When data is being fetched and state is being set on server, it keeps error there in global state forever, which means that if I open new browser I will get the same old error from previous session.
Shouldn't server-side vuex state reset on every request? What am I missing?
I'm confused as to what you mean by "server-side state". Vuex is a client side store. What and why are you saving state to the server?
Furthermore, I cannot tell what you are doing with the code? Is that in a store.js file? In the mutations object?
You would need to wrap that in a vue method like so:
In the Vue file:
methods: {
clicksButton (idx) {
this.$store.commit('read_notification', idx)
}
}
In the store.js file:
const store = new Vuex.Store({
state: {
data: [],
error: null
},
mutations: {
read_notification (state, idx) {
state.data.splice(idx, 1)
}
}
}