0
votes

I'm currently trying to implement a simple theme-switching function in which the active theme is saved in a vuex store state. Upon pressing a button the theme is supposed to switch.

Here is a video with vue-devtools, demonstrating the problem

As you can see in the video the data is successfully changed in the state and the getter returns the correct value, however the computed value of my component doesn't react to the change.

/src/main.js

import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
import Vuex from 'vuex'
import Icon from 'vue-awesome/components/Icon'

Vue.use(Vuex)
Vue.component('icon', Icon)

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

/src/App.vue

<template>
  <div id="app"
       :class="themeName">
    <div id="themeSwitch"
         v-on:click="switchTheme">
      <icon name="lightbulb"
            :class="themeName"></icon>
    </div>
    <router-view/>
  </div>
</template>

<script>
import "vue-awesome/icons/lightbulb"

import { mapState, mapGetters } from "vuex"

var app = {
  name: "App",
  beforeCreate() {
    this.$store.dispatch("LOAD_THEME")
  },
  computed: {
    themeName() {
      return this.$store.getters.GET_THEME
    }
  },
  methods: {
    switchTheme: function(event) {
      this.$store.dispatch("SWITCH_THEME")
    }
  }
};

export default app;
</script>

/src/store/index.js

import Vue from "vue/dist/vue.common.js"
import Vuex from "vuex/dist/vuex.js"
import * as Cookies from "tiny-cookie"

Vue.use(Vuex);

const themes = ["dark", "light"];
const store = new Vuex.Store({
  state: {
    themeName: ''
  },
  actions: {
    LOAD_THEME({ commit, state }) {
      if (state.themeName.length > 0) return

      var themeId = Cookies.getCookie("themeId")
      if (!themeId) commit("SET_COOKIE", themeId = 1)

      commit("SET_THEME", themeId)
    },
    SWITCH_THEME({ commit, state }){
      var id = themes.indexOf(state.themeName) < 1 ? 1 : 0
      commit("SET_THEME", id)
      commit("SET_COOKIE", id)
    }
  },
  getters: {
    GET_THEME: state => {
      return state.themeName
    }
  },
  mutations: {
    SET_COOKIE: (state, id) => {
      Cookies.setCookie("themeId", id, { expires: "1M" })
    },
    SET_THEME: (state, id) => {
      state.themeName = themes[id]
    }
  }
});

export default store;

I tried a few different approaches for the computed property, which I found all over the internet. But none of them made any difference.

computed: mapState({
    themeName: state => state.themeName
  })

computed: {
  ...mapGetters({
    themeName: 'GET_THEME'
  })
}

If I use data instead of computed and I manually set the string it works, but that defeats the purpose of the state if I have to manually set every local variable in every component.

Any help would be appreciated.

1
Why not directly access the state in your computed property, instead of using a getter that returns the state? Like so, this.$store.state.themeNameEric Guan
@EricGuan I tried that as well and it didn't work. But that makes sense now, since the problem was me using two different instances of vue in main.js and index.js. Thanks anyway :)stuffinathor

1 Answers

2
votes

Looks like you are using two different instances of Vue. In main.js you are importing vue but in src/store/index.js you are importing vue/dist/vue.common.jsand telling each one to use Vuex. Try using vue for both imports.