【问题标题】:How to wait for state change before executing next action in Vuex如何在 Vuex 中执行下一个操作之前等待状态更改
【发布时间】:2020-06-15 19:55:14
【问题描述】:

我正在尝试同时登录和获取用户名。以下是它的工作原理:

  1. 第一个操作login 获取访问令牌并更新state.accessToken
  2. 使用state.accessToken 我需要在按下登录时同时获取用户数据(fetchUser),但是当fetchUser 执行时state.accessToken 仍然是null,因为操作是异步的。在执行下一个操作之前等待状态更改的最佳做法是什么?我尝试查找示例,但找到的解决方案不适用于我的案例。

store.js

const store = new Vuex.Store({

state: {
  accessToken: null,
  user: null
},

mutations: {
  authUser (state, userData) {
    state.accessToken = userData.accessToken
  },
  storeUser (state, user) {
    state.user = user
  }
}

actions: {
  login({commit}, authData) {
    axios.post("http://example.com/token/create/", {
        email: authData.email,
        password: authData.password
      })
      .then(res => {
        commit('authUser', {
          accessToken: res.data.access
        })
      })
  },
  fetchUser({commit, state}) {
    axios.get("http://example.com/api/auth/v1/me/", {
      headers: {Authorization: "Bearer "  + state.accessToken}
    })
    .then(res => {
      commit('storeUser', res.data.user)
    })
  }
}

getters: {
  user (state) {
    return state.user
  },
  isAuthenticated(state) {
    return state.accessToken !== null
  }  
}
})

login.vue

<template>
  <form @submit.prevent="submitForm">
    <div v-if="!auth" class="row">
      <input class="col" placeholder="Email" v-model="formInfo.email" type="text"></input>
      <input class="col" placeholder="Password" v-model="formInfo.password" type="password"></input>
      <button class="col" type="submit"  label="Log In"></button>
    </div>
    <div v-else class="row">
      Hello {{ firstname }}
    </div>
  </form>
</template>

<script>
  export default {
    data() {
      return {
        formInfo: {
          email: '',
          password: ''
        }
      };
    },
    methods: {
      submitForm() {
        this.$store.dispatch('login', {email: this.formInfo.email, password: this.formInfo.password})
        this.$store.dispatch('fetchUser')
      }
    },
    computed: {
      auth() {
        return this.$store.getters.isAuthenticated
      },
      firstname() {
        return this.$store.getters.user.firstname
      }    
    }
  }
  };
</script>

【问题讨论】:

标签: vue.js vuejs2 axios vuex


【解决方案1】:

您是否尝试过添加await

  async submitForm() {
    await this.$store.dispatch('login', {email: this.formInfo.email, password: this.formInfo.password});
    await this.$store.dispatch('fetchUser');
  }

它会在获取用户之前等待登录完成

也可以在您的操作方法中添加异步:

async login({commit}, authData) {...}

async fetchUser({commit, state}) {...}

【讨论】:

  • 我认为这个动作必须声明为async login ...
【解决方案2】:

您可以从另一个动作中分派一个动作。

actions: {
  login({commit, dispatch}, authData) {
    axios.post("http://example.com/token/create/", {
        email: authData.email,
        password: authData.password
      })
      .then(res => {
        const accessToken = res.data.access;
        dispatch('fetchUser', accessToken);
        commit('authUser', { accessToken })
      })
  },
  fetchUser({commit, state}, accessToken) {
    axios.get("http://example.com/api/auth/v1/me/", {
      headers: {Authorization: "Bearer "  + accessToken}
    })
    .then(res => {
      commit('storeUser', res.data.user)
    })
  }
}

【讨论】:

    【解决方案3】:

    Evan 的 async/await 解决方案应该可以工作。

    如果有多个页面/组件可以按任何顺序发出动作,并且您不需要在另一个动作完成之前继续执行一个动作,您可以使用将 Promise 存储为状态的策略。然后,您可以访问承诺任何其他取决于完成的操作,并在继续之前等待它。

    所以在 login 中,您将使用 async/await 语法和额外的突变调用:

    const promise = axios.post("http://example.com/token/create/", {
       email: authData.email,
       password: authData.password
    });
    commit('loginPromise', promise);
    const result = await promise;
    

    您需要添加上述突变。 然后在fetchUser,在发出API调用之前:

    await state.loginPromise
    

    这将保证承诺已经完成。当然,您必须处理错误情况。

    【讨论】:

      猜你喜欢
      • 2020-11-26
      • 2018-02-07
      • 2017-02-15
      • 1970-01-01
      • 1970-01-01
      • 2022-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多