简体   繁体   中英

How to access store data in mounted function in vuex

I am having one root component know as App.vue . and another component 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 component. 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.com/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',
  components: {

  },
  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
    })
  },
  components: {
    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.commit('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?

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.commit('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.org/guide/getters.html )

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 
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM