Why action of Vuex returns a promise<pending>? - vue.js

I have an action in Vuex actions which commit a mutation that it take a payload from the component, that is a number of the index for returning an object, it works fine on Vuex js file meaning that shows the selected item on the console, as I said it gets index from the payload,
but on the component, it gives me Promise <Pending>, why that's happening? for now, I do not use any API for my Nuxt/Vue app, but I will, and for now, I just want to know why this is happening and what is the best solution for solving this
Here my Vuex codes:
export const state = () => ({
articles: [
{
uid: 0,
img: 'https://raw.githubusercontent.com/muhammederdem/mini-player/master/img/1.jpg',
link: '/articles/1',
},
{
uid: 1,
img: 'https://raw.githubusercontent.com/muhammederdem/mini-player/master/img/2.jpg',
link: '/articles/2',
},
],
})
export const getters = {
getArticles(state) {
return state.articles
},
}
export const mutations = {
getSpeceficArticle(state, payload) {
return state.articles[payload]
},
}
export const actions = {
getSpeceficArticle({ commit }, payload) {
commit('getSpeceficArticle', payload)
},
}
and here my component codes:
<template>
<div class="article">
{{ getSpeceficArticle() }}
<div class="article__banner">
<img src="" alt="" />
</div>
<div class="article__text">
<p></p>
</div>
</div>
</template>
<script>
export default {
name: 'HomeArticlesArticle',
data() {
return {
item: '',
}
},
// computed: {},
methods: {
async getSpeceficArticle() {
return await this.$store.dispatch('articles/getSpeceficArticle', 0)
},
},
}
</script>

actions are used to update the state they are like mutations but the main difference between them is that actions can include some asynchronous tasks, if you want to get a specific article at given index you should use a getter named getArticleByIndex :
export const getters = {
getArticles(state) {
return state.articles
},
getArticleByIndex:: (state) => (index) => {
return state.articles[index]
}
}
then define a computed property called articleByIndex :
<script>
export default {
name: 'HomeArticlesArticle',
data() {
return {
item: '',
}
},
computed: {
articleByIndex(){
return this.$store.getters.articles.getArticleByIndex(0)
}
},
methods: {
},
}
</script>

#Mohammad if you find yourself using a lot of getters/actions etc from Vuex and they're starting to get a little wordy, you can bring in mapGetters from Vuex and rename your calls to something a little more convenient. So your script would become,
<script>
import { mapGetters } from 'vuex'
export default {
name: 'HomeArticlesArticle',
data() {
return {
item: '',
}
},
computed: {
articleByIndex(){
return this.getArticleByIndex(0)
}
},
methods: {
...mapGetters({
getArticleByIndex: 'articles/getArticleByIndex',
})
},
}
</script>
You can add ...mapGetters, ...mapActions to your computed section also.

since there is no web service call in vuex action, try to remove async and await keywords from the component.
Later when you add a webservice call than you can wrap action body in new Promise with resolve and reject and then you can use async and await in component. let me know if this works for you.

Related

Get object from Vuex at specific index

I am getting an array from Vuex and I want an object at 2 positions.
HTML
<p class="">
{{ MainImg[2].para}}
</p>
Vue
export default {
name: "App",
components: { },
data() {
return {
imageQuery: this.$route.params.image,
};
},
computed: {
...mapGetters("design", {
MainImg: ["singleDesigns"]
})
},
created() {
this.fetchDesigns();
},
mounted() {
console.log(this.MainImg);
},
methods: {
fetchDesigns() {
this.$store.dispatch("design/getSingleDesign", this.imageQuery);
}
}
};
But it shows an undefined error.
And When I add MainImg array in Vue data like this.
data() {
return {
imageQuery: this.$route.params.image,
MainImg:[{para:"1"},{para:"2"},{para:"3"},{para:"4"}]
};
It Works.
P.S.-
Store Code-
export const state = () => ({
designs: [],
})
export const getters = {
singleDesigns(state) {
return state.designs;
}
}
I am not adding Action and Mutation because it works fine with other code.
It looks like the array is empty at the first rendering, so you should add a condition to render it :
<p class="" v-if="MainImg && MainImg.length >= 2">
{{ MainImg[2].para}}
</p>

How make json data available for my Vue dynamic routes

I have a List component where I fetch my date from db/blogs.json:
created() {
fetch('http://localhost:3000/blogs')
.then(response => {
return response.json();
})
.then(data => {
this.blogs = data;
})
},
In my BlogDetail.vue I have:
<script>
export default {
data: () => {
return {
blogId:this.$route.params.id
}
},
computed: {
blog() {
return this.blogs.find(
blog => blog.id === this.blogId
)
}
}
}
</script>
But how do I get the blogs data in this component, which I fetched in the List component?
Because now in the <template> section of my BlogDetail.vue I cannot access e.g. {{ blog.name }}
Update:
I try passing blogs with props:
Now I am accepting a prop in BlogDetails.vue:
props: {
blogs: {
type: Array
}
},
But from where (which component), I have to registering the prop like :blogs="blogs"?
Update 2:
This is what I have so far, link to the sandbox
Here is the working sandbox.
Firstly you need to import JSON data from your JSON file correctly. As:
<script>
import ListItem from "./ListItem";
import Blogs from "../../public/db/blogs.json";
export default {
name: "List",
components: {
ListItem
},
data() {
return {
blogs: Blogs.experiences
};
},
created() {}
};
</script>
Have to send props in the router-link as :
<router-link
:to="{ name: 'BlogDetails', params: { id: blog.id,blog:blog }}">More information
</router-link>
You can send props to the child component in the tag name, in your case:
//LIST component(PARENT)
<tamplate>
<BlogDetail :blogs="blogs"></BlogDetail> //CHILD component
</template>

State variable triggers error when displaying it in template as it's temporarily null when component mounts

My user state variable is an object having several properties such as first_name. I want to display some of these properties in my component template.
I'm assign my state variable to a computed property which I use in template thus:
<template>
<div>
{{ user.first_name }}
</div>
</template>
<script>
import { mapState } from "vuex";
export default {
computed: {
...mapState({
user: state => state.dashboard.user
})
},
beforeMount () {
this.$store.dispatch("dashboard/getUser");
}
};
</script>
Although it works, I get the following error in console:
Error in render: "TypeError: Cannot read property 'title' of null"
I suppose it's because user is null for a split second as component mounts, till it receives info that Vue correctly displays in template. How to avoid the error though?
[EDIT] here are the relevant part of the store:
state: {
user: null
},
...
actions: {
async getUser({ commit }) {
let user = await axios.get(`user`).catch(console.error);
commit("SET_USER", user);
return user;
}
},
In your mapped getter you could default to an empty object like
state => state.dashboard.user || {}
That way things like user.first_name would be undefined rather than attempting to look for a property on the value null
Ok. I've rewritten the code.
store.js
state: {
user: ''
},
mutations: {
SET_USER: (state, user) => {
state.user = user
}
},
actions: {
getUser: (context, user) => {
axios.get('url/to/server')
.then(res => {
context.commit('SET_USER', res.data)
})
.catch(error => {
console.log(error)
})
}
}
Now in your root component (App.vue for example)
import {mapActions} from 'vuex'
export default{
...
mounted() {
this.getUser()
},
methods: {
...mapActions(['getUser'])
}
}
In the component, you wish to use the user data
<template>
<div>
{{user.first_name}}
</div>
<template/>
import {mapState} from 'vuex'
export default{
computed: {
...mapState(['user'])
}
}
This will work.
Hope it helps.

how to get nested getters in vuex nuxt

i have store/index.js like this
new Vuex.Store({
modules: {
nav: {
namespaced: true,
modules: {
message: {
namespaced: true,
state: {
count: 0,
conversations: [],
},
getters: {
getCount: state => {
return state.count;
},
},
mutations: {
updateCount(state) {
state.count++;
},
},
actions: {},
},
requests: {
namespaced: true,
state: {
friends: [],
},
getters: {
getFriends: state => {
return state.friends;
},
},
mutations: {
pushFriends(state, data) {
state.friends.push(data);
},
},
actions: {
pushFriends(commit, data) {
commit('pushFriends', data);
},
},
},
},
},
},
});
i want to use getters in computed property i have tested like this
computed: {
...mapGetters({
count: 'nav/message/getCount',
}),
},
butt getting error
[vuex] unknown getter: nav/message/getCount
what is am missing here
i also want to make separate folder for every modules like my nav have 3 modules message, requests & notifications
i did try but nuxt blow up my codes
I think your index is wrong, the correct thing is to separate the modules independently, something like this:
in your store/index.js
export const state = () => ({
config: {
apiURL: 'https://meuapp.com'
}
})
export const mutations = { }
export const actions = { }
// getters
export const getters = {
test: state => payload => {
if (!payload)
return {
message: 'this is an messagem from index without payload test.', // you don't need pass any payload is only to show you how to do.
result: state.config
}
else
// return value
return {
message: 'this is an message from index test with payload.',
result: state.config, // here is your index state config value
payload: payload // here is yours params that you need to manipulate inside getter
}
}
}
here is your store/navi.js
export const state = () => ({
navi: {
options: ['aaa', 'bbb', 'ccc']
}
})
export const mutations = { }
export const actions = { }
// getters
export const getters = {
test: state => payload => {
if (!payload)
return {
message: 'this is a messagem from nav store without payload test.', // you don't need pass any payload is only to show you how to do.
result: state.navi
}
else
// return value
return {
message: 'this is an messagem from navi test with payload.',
result: state.navi, // here is your index state config value
payload: payload // here is yours params that you need to manipulate inside getter
}
}
}
then in your component you can use as a computed properties:
<template>
<div>
without a paylod from index<br>
<pre v-text="indexTest()" />
with a paylod from index<br>
<pre v-text="indexTest( {name: 'name', other: 'other'})" />
without a paylod from navi<br>
<pre v-text="naviTest()" />
with a paylod from navi<br>
<pre v-text="naviTest( {name: 'name', other: 'other'})" />
access getters from methods<br>
<pre>{{ accessGetters('index') }}</pre>
<pre v-text="accessGetters('navi')" />
<br><br>
</div>
</template>
<script>
import {mapGetters} from 'vuex'
export default {
computed: {
...mapGetters({
indexTest: 'test',
naviTest: 'navi/test'
})
},
methods: {
accessGetters (test) {
if (test && test === 'index' ) {
console.log('test is', test) // eslint-disable-line no-console
return this.indexTest()
}
else if (test && test === 'navi') {
console.log('test is:', test) // eslint-disable-line no-console
return this.naviTest()
}
else {
return 'test is false'
}
}
}
}
</script>
Whenever possible separate your code into smaller parts, one part for each thing. This makes it easier for you to update and keep everything in order.
Hope this helps.
I came here to find a way to access the getters of a module that was nested inside another module in Vue.js and the following solution worked for me:
this.$store.getters['outerModuleName/innerModuleName/nameOfTheGetter']
Maybe this helps someone with a similar problem.

Nuxt.js / Vuex - using Namespace modules in mapActions helper, [vuex] unknown action type: FETCH_LABEL

I am trying to map an action to a component using mapActions helper from vuex. Here is my labels.js vuex module:
export const FETCH_LABELS = 'FETCH_LABELS'
export const FETCH_LABEL = 'FETCH_LABEL'
const state = () => ({
labels: [
{ name: 'Mord Records', slug: 'mord', image: '/images/labels/mord.jpg'},
{ name: 'Subsist Records', slug: 'subsist', image: '/images/labels/subsist.jpg'},
{ name: 'Drumcode Records', slug: 'drumcode', image: '/images/labels/drumcode.png'},
],
label: {} // null
})
const mutations = {
FETCH_LABEL: (state, { label }) => {
state.label = label
},
}
const actions = {
fetchLabel({commit}, slug) {
let label = state.labels.filter((slug, index) => {
return slug == state.labels[index]
})
commit(FETCH_LABEL, { label })
},
}
const getters = {
labels: state => {
return state.labels
},
label: (state, slug) => {
}
}
export default {
state,
mutations,
actions,
getters
}
Here is my component _slug.vue page where I want to map the fetchLabel action:
<template>
<div class="container">
<div class="section">
<div class="box">
<h1>{{ $route.params.slug }}</h1>
</div>
</div>
</div>
</template>
<script>
import { mapGetters, mapActions } from "vuex";
export default {
data() {
return {
title: this.$route.params.slug
};
},
computed: {
// Research
// labels() {
// return this.$store
// }
...mapGetters({
labels: "modules/labels/labels"
})
},
components: {},
methods: {
...mapActions({
fetchLabel: 'FETCH_LABEL' // map `this.add()` to `this.$store.dispatch('increment')`
})
},
created() {
console.log('created')
this.fetchLabel(this.$route.params.slug)
},
head() {
return {
title: this.title
}
},
layout: "app",
}
</script>
<style>
</style>
However inside the created() lifecycle hook at this.fetchLabel(this.$route.params.slug) it throws the following error in the console:
[vuex] unknown action type: FETCH_LABEL
What am I missing or doing wrong? Please help me solve this.
Note that in Nuxt.js:
Modules: every .js file inside the store directory is transformed as a namespaced module (index being the root module).
You are using:
Here is my labels.js vuex module:
with labels.js as you stated above so you'll need to access everything as namespaced modules so your mapAction helper should be like as such:
methods: {
...mapActions({
nameOfMethod: 'namespace/actionName'
})
}
So you would have this:
...mapActions({
fetchLabel: 'labels/fetchLabel'
})
You could also clean it up by doing so for when you'd like to retain the name of your action as your method name.
...mapActions('namespace', ['actionName']),
...
So you would have this:
...mapActions('labels', ['fetchLabel']),
...
In both cases the computed prop should work without a problem.
Your action name is fetchLabel and not FETCH_LABEL (which is a mutation). In mapActions change to
methods: {
...mapActions({
fetchLabel
})
},