Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
3.4k views
in Technique[技术] by (71.8m points)

axios - Vue.js pass $store data from different modules

Hi I need to understand how to "pass" some $store values from settings module to header module, being the $store updated by settingsmodule

I have this app.vue module:

<template>
  <v-app>
    <router-view name="sidebar" />
    <router-view name="header" :handleSettingsDrawer="handleSettingsDrawer" />
    <v-main class="vue-content">
      <v-fade-transition>
        <router-view name="settings" />
      </v-fade-transition>
    </v-main>
    <router-view name="footer" />
    <app-settings-drawer
      :handleDrawer="handleSettingsDrawer"
      :drawer="settingsDrawer"
    />
  </v-app>
</template>

in the <router-view name="header" /> there are a couple of v-menu to select currency and language:

<v-menu offset-y close-on-click>
  <template v-slot:activator="{ on }">
    <v-btn v-on="on" small fab class="mr-3">
      <v-avatar size="30">
        <v-img :src="currentLocaleImg"></v-img>
      </v-avatar>
    </v-btn>
  </template>

  <v-list dense class="langSel">
    <v-list-item
      v-for="(item, index) in langs"
      :key="index"
      @click="handleInternationalization(item.value,item.rtl)"
    >
      <v-list-item-avatar tile class="with-radius" size="25">
        <v-img :src="item.img"></v-img>
      </v-list-item-avatar>
      <v-list-item-title>{{ item.text }}</v-list-item-title>
    </v-list-item>
  </v-list>
</v-menu>

in the script section I import the availableLanguages and availableCurrencies , I set them in data() where I also reference the user:

  data() {
    return {
      items: [
        { icon: "settings", text: "Settings",link: "/settings" },
        { icon: "account_balance_wallet", text: "Account", link:"/tos" },
        { divider: true },
        { icon: "login", text: "Log In",link:"/auth/login" },
        { icon: "desktop_access_disabled", text: "Lock Screen",link:"/auth/lockscreen" },
        { icon: "exit_to_app", text: "Logout",link:"/auth/logout" },
      ],
      langs: availableLocale,
      currs: availableCurrency,
      user: this.$store.state.userdata.user,
    };
  },

then, in computed: I have the 2 functions that should get the current value of curr and lang:

currentLocaleImg() 
{
    return this.langs.find((item) => item.value === this.$store.state.userdata.user.locale).img;
  },
  currentCurrencyImg() {
    return this.currs.find((itemc) => itemc.value === this.$store.state.userdata.user.currency).img;
  }
}

BUT the value of this.$store.state.userdata.user is updated firing the loadData() function mounted in the <router-view name="settings" /> module of App.vue

mounted(){
    this.loadData();
},
methods:
{
async loadData(){
  let jwt=sessionStorage.getItem('jwt');
  try{
      const res = await this.$http.post('/ajax/read_settings.php', {"jwt":jwt});
      this.$store.dispatch("setUser", res.data.user); 
      this.$store.dispatch("setLocale", res.data.user.locale);
      this.$store.dispatch("setCurrency", res.data.user.currency);

  }

the problem is that header module does not have the value of this.$store.state.userdata.user.locale (and .currency) and I get twice the following message:

    vue.runtime.esm.js:1888 TypeError: Cannot read property 'img' of undefined

I do not know how to "pass" the data from one module to the other (or perhaps because the header is rendered before the settings module) and therefore the value of the currency and of the language are not known yet

What's wrong in this procedure? How can I fix it?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There's a race condition in which you try to use data in the template that isn't loaded yet. But first, avoid setting store data directly into component data because the component data won't be updated when the store changes. Replace this:

user: this.$store.state.userdata.user

With a computed:

computed: {
  user() {
    return this.$store.state.userdata.user;
  }
}

You can use v-if to conditionally render only when some data is available:

<v-img :src="currentLocaleImg" v-if="user"></v-img>

The currentLocaleImg computed will not even trigger until user has some data so you will avoid the error. Do the same for currentCurrencyImg if necessary.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...