组件未在商店更改时更新 - Vuex

Posted

技术标签:

【中文标题】组件未在商店更改时更新 - Vuex【英文标题】:Component not updating on store change - Vuex 【发布时间】:2018-08-19 19:49:24 【问题描述】:

TLDR:

如果有帮助,我录制了一段视频来解释我的问题。 https://youtu.be/Qf9Q4zIaox8

导航栏组件不会在商店更改时更新。

我使用 v-if 和 v-else 将组件分为两个部分。当用户登录时显示 v-if,当用户未登录时显示 v-else。

当我登录时,服务器进行身份验证,客户端向存储提交一个突变并设置用户和客户端令牌。设置后,它会将状态为“userIsLoggedIn”的属性设置为 true - 此属性在导航栏组件中计算。由于未知原因,用户登录后导航栏组件不会更新(尽管 isLoggedIn 属性为 true),除非我刷新页面。

导航栏组件:

<template>
    <div class="navbar">
        <div class="container">
            <div class="navbar-brand">
                <h1 class="navbar-item">
                    <router-link to="/" class="has-text-black">Logo</router-link>
                </h1>
            </div>

            <div class="navbar-menu">
                <div class="navbar-end" v-if="isLoggedIn">
                    <div class="navbar-item">
                        <router-link to="/play" class="has-text-black">Play</router-link>
                    </div>
                    <div class="navbar-item">
                        user.balance.toFixed(2)
                    </div>
                    <div class="navbar-item has-dropdown is-hoverable">
                        <a class="navbar-link">
                            user.username
                        </a>

                        <div class="navbar-dropdown">
                            <div class="navbar-item">Profile</div>
                            <div class="navbar-item">Deposit</div>
                            <div class="navbar-item" @click="logout">Logout</div>
                        </div>
                    </div>
                    <div class="navbar-item">
                        FAQ
                    </div>
                </div>

                <div class="navbar-end" v-else>
                    <div class="navbar-item">
                        <router-link to="/login" class="has-text-black">Login</router-link>
                    </div>
                    <div class="navbar-item">
                        <router-link to="/register" class="has-text-black">Register</router-link>
                    </div>
                    <div class="navbar-item">FAQ</div>
                </div>
            </div>
        </div> <!-- container -->
    </div> <!-- navbar -->
</template>

<script>

import mapGetters from "vuex";
export default 
    name: "Navbar",
    data() 
        return 
            user: this.$store.state.user,
        
    ,
    computed: 
        ...mapGetters([
            "isLoggedIn",
        ])
    ,

    methods: 
        logout() 
            this.$store.dispatch("setToken", null);
            this.$store.dispatch("setUser", null);
            this.$router.push(
                path: "/"
            )
        
    

</script>

Vuex 商店:

import Vue from "vue"; 
import Vuex from "vuex";
import createPersistedState from "vuex-persistedstate"

Vue.use(Vuex);

export default new Vuex.Store(
    strict: true, 
    plugins: [
        createPersistedState()
    ],
    state: 
        token: null, 
        user: null, 
        isUserLoggedIn: false, 
    ,
    getters: 
        isLoggedIn(state) 
            return state.isUserLoggedIn;
        
    ,
    
    mutations: 
        setToken(state, token) 
            state.token = token;
            if (token) 
                state.isUserLoggedIn = true;
             else 
                state.isUserLoggedIn = false;
            
        ,
        setUser(state, user) 
            state.user = user; 
        
    ,
    actions: 
        setToken (commit, token) 
            commit("setToken", token);
        ,
        setUser (commit, user) 
            commit("setUser", user);
        
    
)

登录组件:

<template>
  <div class="hero is-large">
      <div class="container">
          <div class="hero-body">
            
              <div class="field">
                  <div class="notification is-warning" v-show="error">error</div>
              </div>

              <h1 class="title">Login</h1>


              <div class="field">
                  <label for="username" class="name">Username</label>
                  <input type="text" class="input" name="username" v-model="username">
              </div>

              <div class="field">
                  <label for="username" class="name">Password</label>
                  <input type="password" class="input" name="password" v-model="password">
              </div>

              <div class="field">
                  <button class="button is-link"
                          @click="login"
                          v-bind:class="'is-loading': pending">Login</button>
              </div>
          </div>
      </div>
  </div>
</template>

<script>

import AuthenticationService from "../Services/AuthenticationService";

export default 
  name: "Login", 

  data () 
      return 
          username: "",
          password: "", 
          error: null, 
          pending: false, 
      
  , 
  methods: 
      async login () 
          try 
            // SET LOADING SPINNER
            this.pending = true; 

            // API REQUEST
            const response = await AuthenticationService.login(
                username: this.username,
                password: this.password, 
            );

            console.log(response);

            // CLEAR FORM
            this.pending = false; 
            this.username = "";
            this.password = ""; 

            this.$store.dispatch("setToken", response.data.token);
            this.$store.dispatch("setUser", response.data.user);

            this.$router.push(
                name: "Landing"
            )
           catch (error) 
              console.log(error);
          
      
  

</script>

【问题讨论】:

显示你做的部分this.$store.dispatch("setToken", &lt;SOMETHING not null&gt;); 好的 - 我已将代码附加到帖子“登录组件” 变异可能有问题吗?您可以使用 VueDevtools 之类的插件在浏览器中检查商店的状态。 我下载了 chrome 工具,按照建议做了。突变工作正常,状态正在正确更新。由于某种原因,一旦状态改变,v-if 和 v-else 块就不会改变。 【参考方案1】:

我想我发现了问题所在。当用户登录时,您没有将 isUserLoggedIn 设置为 true。因此,当用户成功登录时,执行一个操作,然后将 isUserLoggedIn 更改为 true。

动作

setUserLogged (commit) 
 commit("setUserLogged", true);

变异

setUserLogged(state, payload) 
 state.isUserLoggedIn = true

然后在登录组件中的这些行中更改:

this.$store.dispatch("setToken", response.data.token);
this.$store.dispatch("setUser", response.data.user);

到这里:

this.$store.dispatch("setToken", response.data.token);
this.$store.dispatch("setUser", response.data.user);
this.$store.dispatch("setUserLogged");

【讨论】:

如果我错了,请原谅我,但你确定吗?我在 setToken Mutation
  突变中将 isUserLoggedIn 状态设置为 true: setToken(state, token)  state.token = token; if (token)  state.isUserLoggedIn = true;  其他  state.isUserLoggedIn = false;  ,  
更新-无论如何我都尝试了你的建议。我没有工作:( 我在我的项目和作品中做了同样的事情。问题将出在登录组件中。尝试删除异步和所有其他东西,只向服务器发出登录请求。在调用栏中“然后”放你派遣 实际上在更改登录方法之前...在导航栏组件中尝试将“用户”属性设置为空字符串('')并在计算方法中从 vuex 存储中获取用户。为此还需要创建另一个返回用户的吸气剂 嘿,我做到了,它奏效了。我需要设置一个计算方法来从商店获取用户,并且效果很好。太感谢了。一整天都在烦我。

以上是关于组件未在商店更改时更新 - Vuex的主要内容,如果未能解决你的问题,请参考以下文章

如何更新 vuex 存储数组中的对象?

组件道具未在状态更改时更新

点亮的 Web 组件未在属性更改时更新

Vuex 商店自动更新

商店状态更改时反应组件不更新

计算数据未在 Vue 中更新