从 Vuex 动作和组件更改路由

Posted

技术标签:

【中文标题】从 Vuex 动作和组件更改路由【英文标题】:Changing route from Vuex actions and components 【发布时间】:2017-12-01 18:00:06 【问题描述】:

用户通过登录表单成功登录我的应用程序后。我想检查他们是否有个人资料。如果他们这样做,我想将他们发送到新闻页面。如果他们没有有一套,我希望它将他们重定向到“设置”页面。我将如何使用 Vuex 来做到这一点?

我想有几个选择:

1。负责重定向的组件? (感觉不对)

登录.vue

handleFormSubmit () 
this.$store.dispatch('loginFormSubmit', formData)
    .then(() => 
      // This feels a bit gross
      this.$store.dispatch('getUserProfile')
        .then(() => this.$router.push('/news'))
        .catch(() => this.$router.push('/settings'))
    )
    .catch(() => 
      this.loginError = true
    )

2。我会在行动中承担责任吗?

用户操作.js

export const getUserProfile = (commit) => 
  commit(types.USER_PROFILE_REQUEST)
  const options = 
    url: `$API_URL/profile`,
    method: 'GET'
  

  return request(options)
    .then((profileSettings) => 
      // Would I change the router to News here??

      commit(types.USER_PROFILE_SUCCESS, profileSettings)
      return Promise.resolve(profileSettings)
    )
    .catch((error) => 
      // Would I change the router to Settings here??

      commit(types.UI_MENU_HIDE)
      return Promise.reject(error)
    )


export const loginFormSubmit = (dispatch, commit,  email, password ) => 
  console.log(email, password)
  commit(types.USER_LOGIN_REQUEST)
  const options = 
    url: `$API_URL/token`
  
  return request(options)
    .then((response) => 
      dispatch('getUserProfile')
      commit(types.USER_LOGIN_SUCCESS, response.token)
      return Promise.resolve(response.token)
    )
    .catch((error) => 
      commit(types.USER_LOGIN_FAILURE, error)
      return Promise.reject(error)
    )

3。也许它应该放在带有防护装置的路由器中?

登录.vue

handleFormSubmit () 
this.$store.dispatch('loginFormSubmit', formData)
    .then(() => this.$router.push('/news'))
    .catch(() => 
      this.loginError = true
    )

然后在我的路由器中:

const routes = [
      
        path: 'news',
        alias: '',
        component: NewsView,
        name: 'News',
        meta:  description: 'News feed page' ,
        beforeEnter: (to, from, next) => 
          store.dispatch('getUserProfile')
-          .then((resp) => 
-            // Profile set
-            next()
-          )
-          .catch(() => 
-            // No profile set
-            next( name: 'settings' )
-          )
        
      ,
]

4。监听商店变化,然后改变路线

  computed: 
    isAuthenticated () 
      return this.$store.getters.isAuthenticated
    
  ,

  watch: 
    isAuthenticated () 
      this.$router.push('/calendar')
    
  ,
  methods: 
    handleSubmit (formData) 
      // Updates isAuthenticated on success
      this.$store.dispatch('requestAuthToken', formData)
    
  

也许三四号最好?它感觉最干净,但很想知道你们的想法:D

感谢您提前抽出宝贵时间!

【问题讨论】:

你找到最好的方法了吗? 我真的很喜欢 #4 但 #3 可能也可以。实际上,我只是使用#4 来为自己解决这个问题。感谢您发布此信息。抱歉,您没有收到回复。我将这个原始问题标记为收藏。 【参考方案1】:

我认为你想要你的想法 #2 的一个版本。为什么不这样:

    你在Login.vue中调用handleFormSubmit(),它会调度loginFormSubmit()动作。也许此时为 UX 启用 Login.vue 中的加载状态。 如果用户可以登录,则调用getUserProfile(),否则在Login.vue 中显示错误 getUserProfile() 从 API 获取 您可以在操作中通过 API 测试 response,或者将 response 传递给执行此操作的单独突变。 如果用户有个人资料数据,更新staterouter.push('/pathToNews'),否则更新router.push('/pathToSettings')

这里是简化的伪代码来说明这个概念:

// store

  state: 
    userProfile: 
  ,

  mutations: 
    setUserProfile (state, payload) 
      state.userProfile = payload
    
  ,

  actions: 
    getUserProfile() 
      let self = this
      axios.get('$API_URL/token')
      .then(function (response) 
        // test response against what is expected for a populated profile
        if (response.data is a populated user profile) 
          self.commit('setUserProfile', response.data)
          self.router.push('/news')
         else 
          self.router.push('/settings')
        
      )
      .catch(function (error) 
        console.error(error);
        // handle your error
      )
      .finally(function () 
        // always executed
      )
    
  

【讨论】:

【参考方案2】:

我个人使用两种解决方案的组合来解决重定向/处理错误:

    使用axios 拦截器获取最清晰的状态代码:

    import axios from 'axios'
    
    axios.interceptors.response.use(response => response, error => 
        const  status  = error.response
        const errorMessage = error.response.data.message
    
        if (status === Constants.STATUS_CODE_ERROR_NOT_FOUND) 
            router.push('/404')
           return
         else if (status === Constants.STATUS_CODE_ERROR_UNAUTHENTICATED)
          ...
        
        ...
     
    

    在动作中进行检查并在组件中返回以进行重定向或其他必要的操作。

另外,请考虑使用async/await 而不是then/catch

【讨论】:

【参考方案3】:

我的流程:

    组件 (this.$store.dispatch('getProfile'...) 动作 - 服务器 (const response = await fetch ...) 提交对突变的响应 突变保存信息到商店 商店(唯一包含所有信息的地方) 组件(主动从 this.$store.state.user.hasProfile 获取数据并决定做什么)

总结:您发送请求 login, password,然后从服务器接收响应,例如 hasProfile: true/false

    if(hasProfile) 
      // router to
     else  
      // router to
    

【讨论】:

以上是关于从 Vuex 动作和组件更改路由的主要内容,如果未能解决你的问题,请参考以下文章

如何更改路由器在Vue中状态更改时呈现的组件?

Vue.js - 从 API 获取数据并在 Vuex 状态更改时重新加载组件

React,redux 组件不会在路由更改时更新

使用 Lodash.remove 通过 Vuex 突变更改状态不会触发我的 Vue 组件中的反应式重新渲染

一段时间后,如何在小吃店自动关闭时更改 vuex 中的状态

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