[Vuejs]-How to use Vuex with asynchronous computed setter property

0👍

If I understood correctly, the problem you met is both radio buttons have checked effect which is caused by Vue doesn’t render in time.

So the solution is let Vue renders first, then waiting for the promise. Once finished, render again.

Below is two approaches:

  1. uses vm.$forceUpdate

  2. commit one fake value like loading..., Vue will render first (Vue is data driven), after real value comes up, Vue will auto-render again.

Below is one simple demo:

Vue.config.productionTip = false
const store = new Vuex.Store({
  state: {
    theme: "light"
  },
  mutations: {
    theme: (s, p) => (s.theme = p)
  },
  actions: {
    setTheme: async function (context, theme) {
      return new Promise((resolve, reject) => {
        setTimeout(()=> {
          context.commit("theme", theme)
          resolve('done')
        }, 1500)
      })
    }
  }
})

new Vue({
  el: '#app',
  store,
  data() {
    return {
      updatedCount: 1
    }
  },
  computed: {
    theme: {
      get() {
        return this.$store.state.theme
      },
      set(value) {
        //or use this.$forceUpdate() instead
        this.$store.commit("theme", 'loading...') //or other values
        this.setTheme(value)
      }
    }
  },
  updated(){
    console.log('updated', this.updatedCount++)
  },
  methods: {
    ...Vuex.mapActions(["setTheme"])
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<script src="https://unpkg.com/vuex@3.0.1/dist/vuex.js"></script>
<div id="app">
  <div>
    <h3>{{theme}}</h3>
    <input id="light-theme-radio" v-model="theme" type="radio" value="light">
    <label for="light-theme-radio">Light</label>

    <input id="dark-theme-radio" v-model="theme" type="radio" value="dark">
    <label for="dark-theme-radio">Dark</label>
  </div>
</div>
👤Sphinx

Leave a comment