Магазин Vuex / навигационная охрана не работает в первый раз - PullRequest
2 голосов
/ 13 октября 2019

У меня есть панель навигации на приборной панели пользователя, которая требует, чтобы пользователь существовал, чтобы продолжить.

export default new Router({
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/dashboard',
      name: 'dashboard',
      component: Dashboard,
      beforeEnter: (to, from, next) => {
        const user = JSON.parse(store.state.authenticatedUser)
        if(user) {
          console.log("Route accepted.")
          next()
        } else {
          console.log("Route rejected.")
          next('/')
        }
      }
    }
  ]
})

В моей форме входа в систему я отправляю receiveToken, который возвращает токен и связанного пользователя.

<template>
  <v-container>
    <h1 class="display-2">Login</h1>
    <v-form 
      ref="form" 
      v-model="valid" 
      lazy-validation
    >
      <v-col cols="12" md="12">
        <v-row align="center">
          <v-text-field 
            v-model="email" 
            :rules=emailRules 
            label="Email" 
            required 
            dense
          ></v-text-field>
        </v-row>
        <v-row align="center">
          <v-text-field 
            v-model="password"
            label="Password"
            required
            dense
            type="password"
          ></v-text-field>
        </v-row>
      </v-col>
      <v-btn
        @click="login"
      >Login</v-btn>
    </v-form>
  </v-container>
</template>

<script>
export default {
  data: () => ({
    valid: true,
    password: '',
    email: '',
    emailRules: [
      v => !!v || 'Email is required.',
      v => /.+@.+\..+/.test(v) || 'You have entered an invalid email.',
    ],
  }),
  methods: {
    login() {
      this.$store.dispatch('obtainToken', { email: this.email, password: this.password })
      this.$router.push('dashboard')
    }
  }
}
</script>
  actions: {
    logout() {
      this.commit('revokeUser')
      this.commit('revokeToken')
    },
    obtainToken(random, payload) {
      const data = {
        email: payload.email,
        password: payload.password
      }

      api.post(this.state.endpoints.obtainToken, data)
      .then((response => {
        this.commit('updateSessionUser', response.data.user)
        this.commit('updateToken', response.data.token)
      }))
      .catch((e) => {
        console.log(e)
      })
    },

При нажатии submit пользователь получен, но маршрут отклонен, потому что в то время пользователь не существует. Я должен нажать submit во второй раз, что позволит пользователю получить доступ к маршруту dashboard.

enter image description here

Так что я могу собрать извывод состоит в том, что $router.push происходит, когда obtainToken происходит, поэтому они участвуют в гонке. При повторном входе в систему пользователь уже присутствует, поэтому он продолжается. Что я здесь не так делаю?


Я также пытался сделать так, чтобы router.push () также вызывался как разрешение для обещания.

login() {
      this.$store.dispatch('obtainToken', { email: this.email, password: this.password })
      .then(() =>
           this.$router.push('dashboard')
      )
}

Ответы [ 2 ]

2 голосов
/ 14 октября 2019

Похоже, проблема в методе login.

login() {
      this.$store.dispatch('obtainToken', { email: this.email, password: this.password })
      this.$router.push('dashboard')
}

Будут одновременно выполняться оба вызова. Попытка навигации пользователя до результата вызова токена.

login() {
      this.$store.dispatch('obtainToken', { email: this.email, password: this.password })
      .then(() =>
           this.$router.push('dashboard')
      )
}

Когда токен существует, его можно получить из состояния при переходе на панель мониторинга.

1 голос
/ 13 октября 2019

Вызов dispatch является асинхронным.

При смене маршрутизатора он еще не определен.

Так что вам нужно вызвать диспетчер в mounted(), прежде чем переместить другую страницу.

mounted() {
  this.$store.dispatch('obtainToken', { email: this.email, password: this.password })
},
methods: {
  login() {
    this.$router.push('dashboard')
  }
}

Или

methods: {
  login() {
    this.$store.dispatch('obtainToken', { email: this.email, password: this.password }).then(() => this.$router.push('dashboard'))
  }
}

РЕДАКТИРОВАТЬ: Вам необходимо вернуть promise в obtainToken, как показано ниже;

obtainToken(random, payload) {
  ...
  return api.post(this.state.endpoints.obtainToken, data) // just add `return`
  ...
}
...