如何在 vuex 的挂载函数中访问存储数据

Posted

技术标签:

【中文标题】如何在 vuex 的挂载函数中访问存储数据【英文标题】:How to access store data in mounted function in vuex 【发布时间】:2019-11-07 23:39:02 【问题描述】:

我有一个名为App.vue 的根组件。和另一个名为FileUploaderParent.vue 的组件。我正在调用调度承诺以将数据存储在商店中。我在挂载的生命周期钩子下调用调度。

另一方面,我试图在不同组件的挂载函数中访问存储的用户数据。它显示了未定义的错误

我知道,一种解决方法可以是在挂载的函数上调用相同的调度承诺。但是,感觉就像一个黑客,调度调用变得多余。

这是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- max-  />     
      <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>

这是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" >
          </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>

这是商店的样子: 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
        

这是错误的样子:

如何在mounted函数下访问FileUploaderParent.vue中的store数据?

【问题讨论】:

【参考方案1】:

您编写的代码似乎是正确的,但如果您仍然需要答案,您可以使用 watch on store

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

【讨论】:

【参考方案2】:

this.$store.getters 指的是您的 Vuex 商店中的吸气剂。您的 Vuex 商店中没有吸气剂 - 至少在您的示例中看不到任何吸气剂。 (https://vuex.vuejs.org/guide/getters.html)

【讨论】:

我假设 OP 从代码中省略了 getters 部分,并且他具有同名的此属性 (userData)。否则,这可能就是答案! 是的,也许——但还有一个因素是其他人(比如我)看不到的。然后getter 可以返回任何东西——甚至是undefined。解决这个问题会很困难...... :)【参考方案3】:

如何添加一个检查以确定是否需要 API 调用:

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

【讨论】:

它仍然感觉像是一种解决方法......我觉得它与生命周期挂钩有关。但是,我想不通。 Somewhere the reason is the component is getting mounted before the API call gets completed. 如果您想订购组件安装,您可能需要查看async component。 这行得通..有些什么。谢谢!可能正在创建基于异步组件的答案.. 可以为您工作吗?

以上是关于如何在 vuex 的挂载函数中访问存储数据的主要内容,如果未能解决你的问题,请参考以下文章

VUEX(状态管理)

VUEX(状态管理)

Vue() 构造函数中的 vuex“存储”与“数据:存储”,哪个最好?

vuex物理存储在哪里?

如何在 Vuex 存储中存储数据

Vuex 在组件中存储模块状态访问