Am I doing this right? VueX and Vue.js - vue.js

Can someone please help me? I actually don't understand how to initiate localForage (getItem and setItem) in VueX. I have an array on component side, and need to copy it to indexedDB by VueX.
So I have mounted() and watch on the component and trying to activate them by using actions on VueX. Is this possible?
Here is the code on VueX:
enter image description here
and here component side:
enter image description here
enter image description here
export default new Vuex.Store({
state: {
totalTvCount: 10, // The TV inventory
notes: []
},
getters: {
totalTvCount: state => state.totalTvCount,// Here we will create a getter
notes: state => state.notes
},
mutations: {
incTv(state, amount){
state.totalTvCount += amount
} // Here we will create Jenny
},
actions: {
inc(context, amount) {
context.commit('incTv', amount)
}, // Here we will create Larry
setItems(){
localStorage.setItem("notes")
},
getItems(){
localStorage.getItem("notes").then(data => {
this.state.notes = data
})
}
}

Just add a mutation for setting the notes
setNotes(state, notes) {
state.notes = notes
}
then commit the mutation from your action:
getItems({commit}) {
localStorage.getItem("notes")
.then(data => commit('setNotes', data) )
}

Related

Vuex: getter to dispatch action if no data is in the state

I use vuex for my state as well as fetching data and display it in my application.
But I wonder if I'm doing it right. At the moment I dispatch an fetchDataAsync action from the component mounted hook, and I have an getter to display my data. Below is a code example of how I do it currently.
I wonder if it's necessary. What I really want is a getter, that looks at the state, checks if the data is already there and if the data is not there it is able to dispatch an action to fetch the missing data.
The API of vuex does not allow it so I need to put more logic into my components. E.g. if the data is depended of a prop I need a watcher that looks at the prop and dispatches the fetchDataAsync action.
For me it just feels wrong and I wonder if there is a better way.
let store = new Vuex.Store({
state: {
posts: {}
},
mutations: {
addPost(state, post) {
Vue.set(state.posts, post.id, post);
}
},
actions: {
fetchPostAsync({ commit }, parameter) {
setTimeout(
() =>
commit("addPost", { id: parameter, message: "got loaded asynchronous" }),
1000
);
}
},
getters: {
// is it somehow possible to detect: ob boy, I don't have this id,
// I'd better dispatch an action trying to fetch it...?
getPostById: (state) => (id) => state.posts[id]
}
});
new Vue({
el: "#app",
store,
template : "<div>{{ postToDisplay ? postToDisplay.message : 'loading...' }} </div>",
data() {
return {
parameter: "a"
};
},
computed: {
...Vuex.mapGetters(["getPostById"]),
postToDisplay() {
return this.getPostById(this.parameter);
}
},
methods: {
...Vuex.mapActions(["fetchPostAsync"])
},
mounted() {
this.fetchPostAsync(this.parameter);
}
});
I also created a codepen
Personally I think the solution you suggested (adding a watcher that dispatches fetchPostAsync if the post is not found) is the best one. As another commenter stated, getters should not have side effects.

How do correctly add a getter to a Vuex Module?

I'm trying to create a Vuex module whenever I register the module, I get a state is undefined, even though there is nothing calling the getter I had just made. I'm able to call actions correctly with no errors.
This is my module. customer.js
export default {
namespaced: true,
state: {
login: false,
},
getters: {
isLoggedIn: (state) => {
console.log(state);
state.login;
}
},
mutations: {
set_login: (state, login) => {
state.login = login;
},
set_orders: (state, orders) => {
state.orders = orders;
},
},
actions: {
newsletter_subscribe: (context, email) => {
//- TODO
},
}
}
I have register via the registerModule function.
import Customer from './customer';
store.registerModule('customer', Customer, {
preserveState: true
});
Whenever I have developer tools open it just alerts me that.
Uncaught ReferenceError: state is not defined
at isLoggedIn (customer.js:11)
at wrappedGetter (vuex.esm.js:734)
Am I doing anything wrong with my getter?
I've only noticed the getter being called with Vue Dev tools open as I tried putting an alert in the getter to see what else could be triggering without the state being passed in.
I managed to solve it by giving my store a blank state!
const store = new Vuex.Store({
state: {}
});
And registering modules as normal.

What is the right way assign an array in Vue.js?

I have a Vue.js store with an array and a mutation that sets it after is is reloaded via an API:
export default new Vuex.Store({
state: {
triggeredTests: [],
mutations: {
setTriggeredTest(state, data) {
state.triggeredTests = _
.chain(data)
.forEach((item) => {
item.dateFormatted = moment(item.date).format('DD MMMM YYYY');
item.explanationTest = testMapping.get(item.test);
})
.orderBy('date')
.groupBy('date')
.value();
},
},
});
Should I use some specific mutation method to assign the array here to make the bound components refresh correctly?
The triggeredTests property is already in the store (via state:) so Vue has added change listeners and state.triggeredTests = newArray triggers a change.
You only need Vue.set(state, 'triggeredTests', newArray) when a property was not known before.
However changes may not be visible inside a Component that only listens to changes to an item in the previous array.
Using mapState() and using the triggeredTests variable you'll make sure changes to the array are reflected in the component.
computed: mapState({
item: state => state.triggeredTests.find( ... )
})
If you are resetting the entire array you can use Vue.Set() and create a copy of the array. Below is a rough version of this:
export default new Vuex.Store({
state: {
triggeredTests: [],
},
mutations: {
MUTATE_ITEMS: (state, items) => {
Vue.set(state, 'items', [items]);
}
},
actions: {
loadTriggeredTests: (context, data) => {
const newTriggeredTests = array1.map(item => {
return {
dateFormatted : moment(item.date).format('DD MMMM YYYY'),
explanationTest : testMapping.get(item.test)
}
});
context.commit("MUTATE_ITEMS", newTriggeredTests);
}
}
});

Vuex mutation does not commit payload data

I've got a simple VueJS application which uses a Vuex store:
const store = new Vuex.Store({
state: {
organisatie: {}
},
mutations: {
loadOrganisatie (state, payload) {
state.organisatie = payload.organisatie;
console.log(payload.organisatie);
}
}
});
From one of my components I then load the organisation's data to the store as some other components on the page also need its data:
...
created() {
axios.get('/get/'+this.$route.params.orgId)
.then(response => {
this.$store.commit({
type: 'loadOrganisatie',
organisatie: response.data
})
}
...
But the commited state of my Vuex store remains an empty object:
The payload.mutation.organisatie in the devtools is filled with the proper data. But the state.organisatie stays an empty object.
Hope, it will work great for you
mutations: {
loadOrganisatie (state, payload) {
state.organisatie = Object.assign({},payload.organisatie);
console.log(payload.organisatie);
}
}

VueJS - Dynamic State Management multiple instances

I am creating an app and I have a component "Message" which uses a store to get data back from a JSON file (this will be eventually a database) and the component is as follows:
export default {
props: ['message'],
mounted: function() {
this.$store.dispatch("FETCHMESSAGE", this.message);
},
computed: {
title: function() {
return this.$store.state.message;
}
}
}
I have the following mutation:
FETCHMESSAGE: function (context, type)
{
var data = json.type; // Get the data depending on the type passed in
// COMMIT THE DATA INTO THE STORE
}
And I use it as the following:
<MessageApp message="welcome"></MessageApp>
This works for the most part and the correct message is displayed. The issue is when I have multiple instances of MessageApp being called on the same page. They both show the same message (of the last message) being called. E.g.
<MessageApp message="welcome"></MessageApp>
<MessageApp message="goodbye"></MessageApp>
They will each show the goodbye message. I know why this is happening but is it possible to have multiple instances of the store so that this does not happen?
Vuex is "a centralized store for all the components in an application," as the docs say.
So imagine that you have a variable (or many) which you can use and change from all your components.
Also when you want to get properties from state, it is recommended to use getters.
I can't understand what you want to do, but if you want, you can have multiple states, getters, mutations and actions and use them as modules in the store (read more). See below example from Vuex docs:
const moduleA = {
state: { title: '' },
mutations: { changeTitle(state, payload) { state.title = payload } },
actions: { changeTitle({commit}, payload) { commit('changeTitle', payload) } },
getters: { getTitle(state) { return state.title } }
}
const moduleB = {
state: { title: '' },
mutations: { changeTitle(state, payload) { state.title = payload } },
actions: { changeTitle({commit}, payload) { commit('changeTitle', payload) } },
getters: { getTitle(state) { return state.title } }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> `moduleA`'s state
store.state.b // -> `moduleB`'s state