vuex unknown action type: displayArticles - vue.js

Why it doesn't display the json coming from jsonplaceholder?
Did I miss something here? This is just my first time using Vuex.
By the way, I separated the files so that I can debug it easily and I thought it's a good practice for me because I'm planning to implement vuex in a bigger project.
Here is my index.js:
import Vue from 'vue';
import Vuex from 'vuex';
import articles from './modules/articles';
//Load Vuex
Vue.use(Vuex);
//Create store
export default new Vuex.Store({
modules: {
articles
}
})
Here is my articles.js .
import axios from 'axios';
//state
const state = {
articles: []
};
//actions
const actions = {
loadArticles({ commit }) {
axios.get('https://jsonplaceholder.typicode.com/todos')
.then(response => response.data)
.then(articles => {
commit('displayArticles', articles,
console.log(articles))
})
}
};
//mutations
const mutations = {
displayArticles(state, articles) {
state.articles = articles;
}
};
//export
export default {
state,
getters,
actions,
mutations
};
and lastly my home.vue that will display the data from the vuex:
<template>
<section>
<h1>HI</h1>
<h1 v-for="article in articles" :key="article.id">{{article.id}}</h1>
</section>
</template>
<script>
import { mapState } from "vuex";
export default {
mounted() {
this.$store.dispatch("displayArticles");
},
computed: mapState(["articles"])
};
</script>

you have to dispatch the action, so in your .vue file you have to write :
mounted() {
this.$store.dispatch("loadArticles");
},
and to get the list of articles in your component you should use getter in your Store:
const getters = {
getArticles: state => {
return state.articles;
}
and the computed will be like this:
computed:{
getArticlesFromStore(){
return this.$store.getters.getArticles;
}
}
and then you call the computed leement in your HTML:
<h1 v-for="article in getArticlesFromStore" :key="article.id">{{article.id}}</h1>

You are trying to dispatch mutation. You need to use commit with mutations or move your displayArticles to actions. I imagine you meant to dispatch loadArticles?

Related

Nuxt js / Vuex Cannot get state variables on components which is set by nuxtServerInit

I am trying to get the state variable on components which is set by the nuxtServerInit Axios by get method.
store/state.js
export default () => ({
siteData: null
})
store/mutations.js
import initialState from './state'
const mutations = {
SET_SITE_DATA (state, value) {
state.siteData = {
site_title: value.site_title,
logo: value.logo
}
}
}
export default {
...mutations
}
store/getters.js
const getters = {
siteDetails: state => state.siteData
}
export default {
...getters
}
store/actions.js
const actions = {
async nuxtServerInit ({ commit, dispatch }, ctx) {
try {
const host = ctx.req.headers.host
const res = await this.$axios.post('/vendors/oauth/domain/configuration', { domain: host })
commit('SET_SITE_DATA', res.data.data.site_data)
} catch (err) {
console.error(err)
}
},
export default {
...actions
}
}
store/index.js
import Vuex from 'vuex'
import mutations from './mutations'
import getters from './getters'
import actions from './actions'
import state from './state'
const store = () => {
return new Vuex.Store({
state,
getters,
mutations,
actions
})
}
export default store
Here I set SET_SITE_DATA mutation which set siteData state.
components/Header.vue
<template>
<section class="header sticky-top">
<client-only>
{{ siteDetails }}
{{ $store.getters }}
{ logo }}
</client-only>
</section>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters(['siteDetails']),
logo () {
console.log(this.$store.state.siteData)
return this.$store.state.siteData
}
}
}
</script>
Console
I don't know what is happening here. You can see I have consoled the values. So when I reload the page I can get the values but after few seconds all values reset to the null. I want to set those values globally so can access them all over the site. I don't want to call API every time a page changes so I used nuxtServerInit so can set values globally when the page reloads once and can access them.

unable to retrieve mutated data from getter

I'm trying to render a d3 graph using stored data in vuex. but I'm not getting data in renderGraph() function.
how to get data in renderGraph()?
Following is store methods.
store/index.js
import Vue from "vue";
import Vuex from "vuex";
import * as d3 from "d3";
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
subscribers: []
},
getters: {
getterSubscribers: state => {
return state.subscribers;
}
},
mutations: {
mutationSubscribersData: (state, payload) => {
state.subscribers = payload;
}
},
actions: {
actionSubscribersData: async ({ commit }) => {
let subsData = await d3.json("./data/subscribers.json"); // some json fetching
commit("mutationSubscribersData", subsData);
}
}
});
Below is parent component
Home.vue
<template>
<div>
<MyGraph /> // child component rendering
</div>
</template>
<script>
import MyGraph from "./MyGraph.vue";
export default {
components: {
MyGraph
},
};
</script>
Below is child component.
MyGraph.vue
<template>
<div>
<svg width="500" height="400" />
</div>
</template>
<script>
import { mapGetters, mapActions } from "vuex";
export default {
computed: {
...mapGetters(["getterSubscribers"])
},
methods: {
...mapActions(["actionSubscribersData"]),
renderGraph(data) {
console.log(data); // DATA NOT COMING HERE
// MyGraph TO BE RENDERED WITH THIS DATA
}
},
mounted() {
this.actionSubscribersData();
this.renderGraph(this.getterSubscribers);
}
};
</script>
I have tried mounted, created lifecycle hooks. but did not find data coming.
There is race condition. actionSubscribersData is async and returns a promise. It should be waited for until data becomes available:
async mounted() {
await this.actionSubscribersData();
this.renderGraph(this.getterSubscribers);
}
There must be delay for the actionSubscribersData action to set value to store. Better you make the action async or watch the getter. Watching the getter value can be done as follows
watch:{
getterSubscribers:{ // watch the data to set
deep:true,
handler:function(value){
if(value){ // once the data is set trigger the function
this.renderGraph(value);
}
}
}
}

Nuxt.js unknown store

I'm new to VueJS and try to use the store with NuxtJS.
So, i want to get this (https://nuxtjs.org/guide/vuex-store/) to work.
My store ./store/index.js
import { mapActions, mapGetters } from 'vuex'
export const state = () => ({
temperature: '1234'
})
export const mutations = {setName
setTemperature(state, payload) {
state.temperature = payload
}
}
export const actions = {
getWeatherData({ commit }) {
console.log("set weather to 123")
commit('setTemperature', '123')
}
}
export const getters = {
storeTemperature(state) {
return state.temperature
}
}
export const mixin = {
computed: {
...mapGetters([{
myTemperature: 'weather/storeTemperature'
}])
},
methods: {
...mapActions({
loadWeatherData: 'weather/getWeatherData'
})
}
}
export default mixin
Now i have a simple component to display the temperature:
<template>
<div class="label">
{{ testB }}
</div>
</template>
<style lang="scss" src="./Label.scss"></style>
<script>
import { mixin as WeatherMixin } from '../../store'
export default {
name: 'Label',
//mixins: [WeatherMixin],
props: {
content: {
Type: String,
default: ''
}
},
computed: {
testB () {
return this.$store.state.store.temperature
}
}
}
</script>
I tried to use mapGetters and use it like:
testB () {
return this.myTemperature
}
but this didn't work.
So i tried to use mapState via:
// store
computed: {
...mapState({ temperature: 'temperature' })
}
and use it in the component like
<div class="label">
{{ temperature }}
</div>
But i always didn't get the default value of 1234.
The Vue Console didn't find the store:
But forward to the NuxtJS documentation:
Nuxt.js will look for the store directory, if it exists, it will:
Import Vuex,
Add the store option to the root Vue instance.
What i need to get the store working as expected and how i can access the store state properties? Did i miss something?
To properly manage Vuex in NuxtJS, use namespaced Vuex modules, to keep your state logic properly organized.
For a globally accessible state, you can add these to the ./store/index.js file, while for namespaced modules create a folder with a name of your namespaced module (Preferably no spaces.), then in this folder create files with names actions.js for actions, state.js for states, getters.js for getters and mutations.js for your mutations and export default from each.
You can then access the namespaced state with this.$store.state.<NAMESPACED MODULE NAME>.<STATE VARIABLE>

How to pass data Between vue single file component

I have (my first) app in vue that get data from api and render some select elements.
I want to separe each box to another file (one file for get data from api, second for render select, third for render list).
How can i pass data from
I tried to get data from instance of api:
export default {
props: {
filters: apiIntance.$data.kpis.filters,
For this moment i have something like that:
<!-- src/components/Filters.vue -->
<template>
<div class="filters">
<label v-bind:key="filter.id" v-for="filter in filters">
<select class="js-selectbox">
<option v-bind:value="item.id" v-bind:key="item.id" v-for="item in filter.items">{{item.name}}</option>
</select>
</label>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import Api from './ApiTest.vue';
export default {
props: {
filters: //Get Data from ApiTest.vue
},
};
</script>
<!-- src/components/ApiTest.vue -->
export default Vue.extend({
data(): DataObject {
return {
kpis: {
...
},
};
},
Have you some tips how to get data in one file and spread it for other files?
You might be looking for Vuex which is a vue data management plugin that all your components will have access to
import Vue from 'vue'
import Vuex from 'vue'
Vue.use(Vuex)
const store = new Vuex.Store({
// data will be stored here
state: {
apiData: null,
},
mutations: {
// you call this mutation to add data
apiData(state) {
state.apiData = apiData
}
},
getters: {
// a getter for the data
apiData(state) {
retrun state.apiData
}
}
})
// new Vue({...,store})
you can add data to the store immediately after the fetching with :
this.$store.commit('apiData',yourdatahere)
and then access/get it on any component with :
this.$store.getters.apiData
you can read more about Vuex
There are numerous ways, to name a few
one file for get data from api don't need to be a vue instance. You may want to add more hooks.
// ApiService.ts
export const ApiService = { getData: () => {/**/} }
// src/components/Filters.vue
...
<script lang="ts">
import Vue from 'vue';
import {ApiService} from '#/.../ApiService'
export default {
data: () => ({
filters: []
}),
created() {
ApiService.getData().then(data => this.filters = data)
}
};
</script>
You can certainly make a Vue instance to provide data, to make it reactive and component independent from data logic. For example:
// ApiService.ts
const ApiService = new Vue({
data: () => ({
filters: []
}),
created() {
request().then(data => this.filters = data)
}
})
// src/components/Filters.vue
...
<script lang="ts">
import Vue from 'vue';
import {ApiService} from '#/.../ApiService'
export default {
computed: {
filters() {
return ApiService.filters
}
}
};
</script>

Vuex. Again: Computed properties are not updated after Store changes. The simplest example

I did really read all Google!
Store property "sProp" HAS initial value (=10);
I use Action from component to modify property;
Action COMMITS mutation inside the Store Module;
Mutation uses "Vue.set(..." as advised in many tickets
Component uses mapState, mapGetters, mapActions (!!!)
I also involve Vuex as advised.
I see initial state is 10. But it is not changed after I press button.
However if I console.log Store, I see it is changed. It also is changed in memory only once after the 1st press, but template always shows 10 for both variants. All the other presses do not change value.
Issue: my Computed Property IS NOT REACTIVE!
Consider the simplest example.File names are in comments.
// File: egStoreModule.js
import * as Vue from "vue/dist/vue.js";
const state = {
sProp: 10,
};
const getters = {
gProp: (state) => {
return state.sProp;
}
};
const mutations = {
//generic(state, payload) {},
mProp(state, v) {
Vue.set(state, "sProp", v);
},
};
const actions = {
aProp({commit}, v) {
commit('mProp', v);
return v;
},
};
export default {
namespaced: true
, state
, getters
, mutations
, actions
}
And it's comsumer:
// File: EgStoreModuleComponent.vue
<template>
<!--<div :flag="flag">-->
<div>
<div><h1>{{sProp}} : mapped from Store</h1></div>
<div><h1>{{$store.state.egStoreModule.sProp}} : direct from Store</h1></div>
<button #click="methChangeProp">Change Prop</button>
<button #click="log">log</button>
</div>
</template>
<script>
import {mapActions, mapGetters, mapState} from "vuex";
export default {
name: 'EgStoreModuleComponent',
data() {
return {
flag: true,
};
},
computed: {
...mapState('egStoreModule', ['sProp']),
...mapGetters('egStoreModule', ['gProp'])
},
methods: {
...mapActions('egStoreModule', ['aProp']),
methChangeProp() {
const value = this.sProp + 3;
this.aProp(value);
//this.flag = !this.flag;
},
log() {
console.log("log ++++++++++");
console.log(this.sProp);
},
}
}
</script>
<style scoped>
</style>
Here is how I join the Store Module to Application:
// File: /src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import collection from "./modules/collection";
import egStoreModule from "./modules/egStoreModule";
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {},
getters : {},
mutations: {},
actions : {},
modules : {
collection,
egStoreModule
}
});
Finally: main.js
import Vuex from 'vuex'
import {store} from './store'
//...
new Vue({
el: '#app',
router: router,
store,
render: h => h(App),
})
It all works if only I use "flag" field as shown in comments.
It also works if I jump from page and back with Vue-router.
async/await does not help.
I deleted all under node_modules and run npm install.
All Vue/Vuex versions are the latest.