最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to access store data in mounted function in vuex - Stack Overflow

programmeradmin2浏览0评论

I am having one root ponent know as App.vue. and another ponent named as FileUploaderParent.vue. I am calling a dispatch promise to store the data in the store. I am calling dispatch under mounted lifecycle hook.

On the other side, I am trying to access stored user data in the mounted function of a different ponent. It shows the error of undefined

I know, a work around can be to call same dispatch promise on the mounted function. But, It feels like a hack and the dispatch call is getting redundant.

Here is the code for App.vue:

<template>
  <v-app>
    <v-navigation-drawer  v-model="drawer" app temporary >
      <v-img :aspect-ratio="16/9" src=".jpg">
        <v-layout pa-2 column fill-height class="lightbox gray--text">
          <v-spacer></v-spacer>
          <v-flex shrink>
            <!-- <div class="subheading">{{this.$store.getters.userData.name}}</div> -->
            <!-- <div class="body-1">{{this.$store.getters.userData.email}}</div> -->
          </v-flex>
        </v-layout>
      </v-img>
      <v-list>
        <template v-for="(item, index) in items">
          <v-list-tile :href="item.href" :to="{name: item.href}" :key="index">
            <v-list-tile-action>
              <v-icon light v-html="item.icon"></v-icon>                
            </v-list-tile-action>
            <v-list-tile-content>
              <v-list-tile-title v-html="item.title"></v-list-tile-title>
            </v-list-tile-content>
          </v-list-tile>
        </template>
      </v-list>
    </v-navigation-drawer>
    <v-toolbar color="white" light :fixed=true>
      <v-toolbar-side-icon @click.stop="drawer = !drawer"></v-toolbar-side-icon>
      <v-img :src="require('@/assets/mad_logo.png')" max-width="80px" max-height="41px"  />     
      <v-toolbar-title class="black--text justify-center" > <h1>MeshApp</h1></v-toolbar-title>
      <v-spacer></v-spacer>
      <v-avatar color="primary">
        <!-- <span class="white--text headline">{{this.avatar.slice(0,2)}}</span>          -->
      </v-avatar>   
    </v-toolbar>
    <v-content style="margin-top: 60px;">
      <v-fade-transition mode="out-in">
        <router-view></router-view>
      </v-fade-transition>
    </v-content>
  </v-app>  
</template>

<script>
export default {
  name: 'app',
  ponents: {

  },
  data() {
    return {   
      avatar: '',    
      drawer: false,
      items: [
        {
          href: 'home',
          router: true,
          title: 'home',
          icon: 'grid_on',
        },
        {
          href: 'view_volunteers',
          router: true,
          title: 'View Volunteer',
          icon: 'group'
        },
        {
          href: 'profile',
          router: true,
          title: 'profile',
          icon: 'account_circle',
        }, 
        {
          href: 'logout',
          router: true,
          title: 'Logout',
          icon: 'toggle_off',
        }

      ]
    }
  },
  props: [], 
  mounted() {
   this.$store.dispatch('getUserData').
    then(() => {      
     let findAvatar = this.$store.getters.userData.name.split(" ")
     let createAvatar = ''
     for(let i = 0; i < findAvatar.length; i++) {
       createAvatar = createAvatar + findAvatar[i].slice(0,1)
     }
     this.avatar = createAvatar
     console.log(this.avatar)
     // this.$store.dispatch('getUserId', id) 
   })    
  }   
}

</script>

<style scoped>

v-content {
  margin-top: 60px !important;
}
</style>

Here is the code for FileUploaderParent.vue:

<template>
  <v-layout class="text-xs-center ">
    <v-flex>
      <image-input v-model="avatar">
        <div slot="activator">
          <v-avatar color = "primary" size="150px" v-ripple v-if="!avatar" class=" mb-3">
            <h1 class="white--text"><span>{{this.defaultAvatar}}</span></h1>
          </v-avatar>
          <v-avatar size="150px" v-ripple v-else class="mb-3">
            <img :src="avatar.imageURL" alt="avatar">
          </v-avatar>
        </div>
      </image-input>
      <v-slide-x-transition>
        <div v-if="avatar && saved == false">
          <!-- Stores the Image and changes the loader -->
          <v-btn  class="primary" @click="uploadImage" :loading="saving">Save Avatar</v-btn>
        </div>
      </v-slide-x-transition>
    </v-flex>
  </v-layout>
</template>

<script>
import ImageInput from './FileUploaderChild.vue'

export default {
  name: 'app',
  data () {
    return {
      defaultAvatar: '',
      avatar: null,
      saving: false,
      saved: false
    }
  },
  mounted() {
     this.$store.dispatch('getUserData').
    then(() => {
      let findAvatar = this.$store.getters.userData.name.split(" ")
      let createAvatar = ''
      for(let i = 0; i < findAvatar.length; i++) {
        createAvatar = createAvatar + findAvatar[i].slice(0,1)
      }
      this.defaultAvatar = createAvatar
    })
  },
  ponents: {
    ImageInput: ImageInput
  },
  watch:{
    avatar: {
      handler: function() {
        this.saved = false
      },
      deep: true
    }
  },
  methods: {
    uploadImage() {
      this.saving = true
      setTimeout(() => this.savedAvatar(), 1000)
    },
    savedAvatar() {
      this.saving = false
      this.saved = true
    }
  }
}
</script>

<style>

</style>

This is how the store looks like: store.js

actions: {
        getUserData(context)  {
            return new Promise((resolve, reject) => {
                axios.get('/'+this.state.userId, {
                    headers: {
                        'Content-Type': 'application/json'               
                    },
                    auth: {
                        username: 'someusername',
                        password: 'pass'
                    }    
                }).
                then(response => {
                    contextmit('storeUserData', response.data.data.users)                    
                    resolve(response);  // Let the calling function know that http is done. You may send some data back
                }).catch(error => {
                    reject(error);
                })        
            })
        }
},
mutations: {
        storeUserData(state, data) {
            state.userData = data
        }
}

This is how the error looks like:

How do i access store data in FileUploaderParent.vue under mounted function?

I am having one root ponent know as App.vue. and another ponent named as FileUploaderParent.vue. I am calling a dispatch promise to store the data in the store. I am calling dispatch under mounted lifecycle hook.

On the other side, I am trying to access stored user data in the mounted function of a different ponent. It shows the error of undefined

I know, a work around can be to call same dispatch promise on the mounted function. But, It feels like a hack and the dispatch call is getting redundant.

Here is the code for App.vue:

<template>
  <v-app>
    <v-navigation-drawer  v-model="drawer" app temporary >
      <v-img :aspect-ratio="16/9" src="https://image.freepik./free-vector/spot-light-background_1284-4685.jpg">
        <v-layout pa-2 column fill-height class="lightbox gray--text">
          <v-spacer></v-spacer>
          <v-flex shrink>
            <!-- <div class="subheading">{{this.$store.getters.userData.name}}</div> -->
            <!-- <div class="body-1">{{this.$store.getters.userData.email}}</div> -->
          </v-flex>
        </v-layout>
      </v-img>
      <v-list>
        <template v-for="(item, index) in items">
          <v-list-tile :href="item.href" :to="{name: item.href}" :key="index">
            <v-list-tile-action>
              <v-icon light v-html="item.icon"></v-icon>                
            </v-list-tile-action>
            <v-list-tile-content>
              <v-list-tile-title v-html="item.title"></v-list-tile-title>
            </v-list-tile-content>
          </v-list-tile>
        </template>
      </v-list>
    </v-navigation-drawer>
    <v-toolbar color="white" light :fixed=true>
      <v-toolbar-side-icon @click.stop="drawer = !drawer"></v-toolbar-side-icon>
      <v-img :src="require('@/assets/mad_logo.png')" max-width="80px" max-height="41px"  />     
      <v-toolbar-title class="black--text justify-center" > <h1>MeshApp</h1></v-toolbar-title>
      <v-spacer></v-spacer>
      <v-avatar color="primary">
        <!-- <span class="white--text headline">{{this.avatar.slice(0,2)}}</span>          -->
      </v-avatar>   
    </v-toolbar>
    <v-content style="margin-top: 60px;">
      <v-fade-transition mode="out-in">
        <router-view></router-view>
      </v-fade-transition>
    </v-content>
  </v-app>  
</template>

<script>
export default {
  name: 'app',
  ponents: {

  },
  data() {
    return {   
      avatar: '',    
      drawer: false,
      items: [
        {
          href: 'home',
          router: true,
          title: 'home',
          icon: 'grid_on',
        },
        {
          href: 'view_volunteers',
          router: true,
          title: 'View Volunteer',
          icon: 'group'
        },
        {
          href: 'profile',
          router: true,
          title: 'profile',
          icon: 'account_circle',
        }, 
        {
          href: 'logout',
          router: true,
          title: 'Logout',
          icon: 'toggle_off',
        }

      ]
    }
  },
  props: [], 
  mounted() {
   this.$store.dispatch('getUserData').
    then(() => {      
     let findAvatar = this.$store.getters.userData.name.split(" ")
     let createAvatar = ''
     for(let i = 0; i < findAvatar.length; i++) {
       createAvatar = createAvatar + findAvatar[i].slice(0,1)
     }
     this.avatar = createAvatar
     console.log(this.avatar)
     // this.$store.dispatch('getUserId', id) 
   })    
  }   
}

</script>

<style scoped>

v-content {
  margin-top: 60px !important;
}
</style>

Here is the code for FileUploaderParent.vue:

<template>
  <v-layout class="text-xs-center ">
    <v-flex>
      <image-input v-model="avatar">
        <div slot="activator">
          <v-avatar color = "primary" size="150px" v-ripple v-if="!avatar" class=" mb-3">
            <h1 class="white--text"><span>{{this.defaultAvatar}}</span></h1>
          </v-avatar>
          <v-avatar size="150px" v-ripple v-else class="mb-3">
            <img :src="avatar.imageURL" alt="avatar">
          </v-avatar>
        </div>
      </image-input>
      <v-slide-x-transition>
        <div v-if="avatar && saved == false">
          <!-- Stores the Image and changes the loader -->
          <v-btn  class="primary" @click="uploadImage" :loading="saving">Save Avatar</v-btn>
        </div>
      </v-slide-x-transition>
    </v-flex>
  </v-layout>
</template>

<script>
import ImageInput from './FileUploaderChild.vue'

export default {
  name: 'app',
  data () {
    return {
      defaultAvatar: '',
      avatar: null,
      saving: false,
      saved: false
    }
  },
  mounted() {
     this.$store.dispatch('getUserData').
    then(() => {
      let findAvatar = this.$store.getters.userData.name.split(" ")
      let createAvatar = ''
      for(let i = 0; i < findAvatar.length; i++) {
        createAvatar = createAvatar + findAvatar[i].slice(0,1)
      }
      this.defaultAvatar = createAvatar
    })
  },
  ponents: {
    ImageInput: ImageInput
  },
  watch:{
    avatar: {
      handler: function() {
        this.saved = false
      },
      deep: true
    }
  },
  methods: {
    uploadImage() {
      this.saving = true
      setTimeout(() => this.savedAvatar(), 1000)
    },
    savedAvatar() {
      this.saving = false
      this.saved = true
    }
  }
}
</script>

<style>

</style>

This is how the store looks like: store.js

actions: {
        getUserData(context)  {
            return new Promise((resolve, reject) => {
                axios.get('http://someurl.in/api/v1/users/'+this.state.userId, {
                    headers: {
                        'Content-Type': 'application/json'               
                    },
                    auth: {
                        username: 'someusername',
                        password: 'pass'
                    }    
                }).
                then(response => {
                    context.mit('storeUserData', response.data.data.users)                    
                    resolve(response);  // Let the calling function know that http is done. You may send some data back
                }).catch(error => {
                    reject(error);
                })        
            })
        }
},
mutations: {
        storeUserData(state, data) {
            state.userData = data
        }
}

This is how the error looks like:

How do i access store data in FileUploaderParent.vue under mounted function?

Share Improve this question asked Jun 26, 2019 at 5:28 abhigyan nayakabhigyan nayak 1,4448 gold badges26 silver badges38 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 1

The code you have written seems right, but if you still need an answer you can use watch on store

this.$store.watch(() => this.$store.state.userData, async () => {
 //do your code here 
});

How about adding a check that determines if an API call is required:

actions: {
  getUserData(context) {
    return new Promise((resolve, reject) => {
      // Be sure to set the default value to `undefined` under the `state` object.
      if (typeof this.state.userData === 'undefined') {
        axios
          .get('http://someurl.in/api/v1/users/' + this.state.userId, {
            headers: {
              'Content-Type': 'application/json'
            },
            auth: {
              username: 'someusername',
              password: 'pass'
            }
          })
          .then(response => {
            context.mit('storeUserData', response.data.data.users);
            resolve(response.data.data.users);
          })
          .catch(error => {
            reject(error);
          });
      }
      else {
        resolve(this.state.userData);
      }
    })
  }
}

The this.$store.getters refers to a getter in your Vuex store. You have no getters in your Vuex store - at least none can be seen in your sample. (https://vuex.vuejs/guide/getters.html)

发布评论

评论列表(0)

  1. 暂无评论