Search code examples
javascriptvue.jsvuexvue-router

Property or method "X" is not defined on the instance with vuex and vue router


This problem is annoying me, i'm new with Vue and i'm trying to make a simple app to get practice.

Right now I'm using Vuex and Vue Router, here is the code:

The routes file, very simple, just a lazy load for the routes that aren't home.

import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'

Vue.use(Router)

export default new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/tracks',
      name: 'tracks',
      component: () => import(/* webpackChunkName: "about" */ './views/Tracks.vue')
    }
  ]
})

The view component, it just render the view childs:

<template>
  <div id="tracks">
    <logo></logo>
    <search></search>
    <songs></songs>
  </div>
</template>

<script>
import Logo from '@/components/Logo.vue'
import Search from '@/components/Search.vue'
import Songs from '@/components/Songs.vue'

export default {
  name: 'tracks',
  components: { Logo, Search, Songs }
}
</script>

The songs component, this is the container where i make the logic (just list things right now)

<template>
  <section id="track-list" class="columns is-centered">
    <div class="column is-4" v-show="!songList.length">
      <div class="notification is-danger">
        No tracks loaded :(
      </div>
    </div>
  </section>
</template>

<script>
import { mapState } from 'vuex'
import SongCard from './SongCard.vue'

export default {
  name: 'songs',
  components: { SongCard },
  computed: {
    ...mapState([ 'songs' ])
  }
}
</script>

I think the problem is in the rendering cycle, where the component is mounted the data isn't loaded yet, but this isn't async data (not mine, at least) but hardcoded in the state, initalized as empty array:

const state = {
  songList: [ ],
  song: null
}

// actions
const actions = {

}

// mutations
const mutations = {
  // [tracks.GET_TOP](state, payload) {},

  // [tracks.GET_TRACK](state, payload) {}
}

export default {
  namespaced: true,
  state,
  actions,
  mutations
}

Since i use Vuex, i don't use the data() {} key, else i use computed... what can i do here? I'm lost.

Edit, here is the complete store file:

import Vue from 'vue'
import Vuex from 'vuex'

import artists from './modules/artists'
import songs from './modules/songs'

import actions from './actions'
import mutations from './mutations'

Vue.use(Vuex)

export default new Vuex.Store({
  modules: {
    artists,
    songs,
    countries: {
      state: {
        selected: 'Mexico',
        list: [
          { value: 'spain', name: 'España' },
          { value: 'mexico', name: 'México' },
          { value: 'argentina', name: 'Argentina' }
        ]
    }
    }
  },
  actions,
  mutations
})

Solution

  • The main issue here is that songs is not a state, it's a namespaced module so it cannot be access directly like ...mapState(['songs']).

    To map state of the songs module of the store, we use mapState helper syntax intended for use with namespaced module:

    computed: {
      ...mapState('some/nested/module', {
        a: state => state.a,
        b: state => state.b
      })
    }
    

    So, the correct syntax with respect to this question would be:

    ...mapState('songs', [ 'song', 'songList' ])
    

    Note that you can also pass an object instead of array just like in the example above.

    For more, refer this.