简体   繁体   中英

Vuex child components cannot access this.$store (undefined)

I followed these instructions in the Vuex documentation for accessing the Vuex state from my Vue components... but whenever I use this.$store.something in my components, I get TypeError: Cannot read property 'something' of undefined (see screenshot at the bottom of this post).

The documentation says,

By providing the store option to the root instance, the store will be injected into all child components of the root and will be available on them as this.$store

...but that functionality does not seem to be working in my application.

Here is my code:

main.js

import Vue from 'vue'
import App from './App'
import axios from 'axios'
import router from './router'
import store from './store'

Vue.config.productionTip = false
axios.defaults.baseURL = 'http://localhost:3000'

new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

store.js

import Vue from 'Vue'
import Vuex from 'vuex'
import router from './router'
import axios from 'axios'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    token: null
  },
  mutations: { // setters (synchronous)
    setToken (state, userData) {
      state.token = userData.token
    },
    clearToken (state) {
      state.token = null
    }
  },
  actions: { // asynchronous tasks
    signup (authData) {
      axios.post('/user/signup', {
        email: authData.email,
        password: authData.password
      })
        .then(res => {
          if (res.status === 201) {
            // what happens if signup succeeds?
          } else {
            // what happens if signup fails?
          }
        })
        .catch(error => console.log(error))
    },
    setLogoutTimer ({commit}, expiresIn) {
      setTimeout(() => {
        commit('clearToken')
      }, expiresIn * 1000)
    },
    login ({commit, dispatch}, authData) {
      axios.post('/user/login', {
        email: authData.email,
        password: authData.password
      })
        .then(res => {
          console.log(res)

          // set token with timeout
          const now = new Date()
          const tokenExpiration = new Date(now.getTime() + res.data.expiresIn * 1000)
          localStorage.setItem('token', res.data.token)
          localStorage.setItem('tokenExpiration', tokenExpiration)
          commit('setToken', { token: res.data.token })
          dispatch('setLogoutTimer', res.data.expiresIn)

          // redirect to dashboard
          router.replace('/dashboard')
        })
        .catch(error => console.log(error))
    },
    tryAutoLogin ({commit}) {
      const token = localStorage.getItem('token')
      if (!token) {
        return
      }
      const tokenExpiration = localStorage.getItem('tokenExpiration')
      const now = new Date()
      if (now >= tokenExpiration) {
        return
      }
      commit('setToken', { token: token })
    },
    logout ({commit}) {
      commit('clearToken')
      localStorage.removeItem('token')
      localStorage.removeItem('tokenExpiration')
      router.replace('/login')
    }
  },
  getters: {
    isAuthenticated (state) {
      return state.token !== null
    }
  }
})

App.vue

<template>
  <div id="app">
    <app-header/>
    <router-view/>
  </div>
</template>

<script>
import Header from './components/Header.vue'

export default {
  name: 'App',
  components: {
    'app-header': Header
  },
  created () {
    this.$store.dispatch('tryAutoLogin')
  }
}
</script>

Header.vue

<template>
  <header id="header">
    <div class="logo">
      <router-link to="/">Home</router-link>
    </div>
    <nav>
      <ul>
        <li v-if="!auth">
          <router-link to="/signup">Sign Up</router-link>
        </li>
        <li v-if="!auth">
          <router-link to="/login">Login</router-link>
        </li>
        <li v-if="auth">
          <router-link to="/dashboard">Dashboard</router-link>
        </li>
        <li v-if="auth">
          <a @click="onLogout">Logout</a>
        </li>
      </ul>
    </nav>
  </header>
</template>

<script>
export default {
  computed: {
    auth () {
      return this.$store.state.token !== null
    }
  },
  methods: {
    onLogout () {
      this.$store.dispatch('logout')
    }
  },
  watch: {
    $route () {
      console.log('STORE: ', this.$store.state)
    }
  }
}
</script>

The errors:

错误

Use Destructuring when importing store into your main.js file.

Change your code from

import Vue from 'vue'
import App from './App'
import axios from 'axios'
import router from './router'
import store from './store'

Vue.config.productionTip = false
axios.defaults.baseURL = 'http://localhost:3000'

new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

To

import Vue from 'vue'
import App from './App'
import axios from 'axios'
import router from './router'
import { store } from './store' //Added Destructuring

Vue.config.productionTip = false
axios.defaults.baseURL = 'http://localhost:3000'

new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

It worked for me..Hope it works for you as well!

Everything looks good in your code. However in your main.js file change the following code

new Vue({
 el: '#app',
 router,
 store,
 components: { App },
 template: '<App/>'
})

to

new Vue({
   el: "#app",
   router,
   store,
   render: h => h(App)
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM