4
votes

I have a component, which looks like this:

export default {
  name: 'todos',
  props: ['id'],
  created () {
    this.fetchData()
  },
  data() {
    return {
    }
  },
  computed: {
    todos () {
      return this.$store.state.todos[this.id]
    }
  },
  methods: {
    async fetchData () {
      if (!this.$store.state.todos.hasOwnProperty(this.id)) {
        await this.$store.dispatch('getToDos', this.id)
      }
    }
  }
}

This is what's happening:

  1. The component receives an id via props.

When the component loads I need to fetch some data based on the id

  1. I have a created() hook from where I call a function fetchData() to fetch the data.

  2. In methods, the fetchData() function dispatches an action to get the data. This gets and stores the data in Vuex store.

  3. The computed property todos gets the data for this id.

The problem is that when the page first loads, the computed property todos shows up as undefined. If I change the page (client side) then the computed property gets the correct data from the store and displays it.

I am unable to understand why computed property doesn't update?

2
Can you show the code for the getToDos function aswell? - T. Dirks
@T.Dirks getToDos is a Vues action that calls an external api for the data and then commits a mutation. getToDos ({commit}, payload) { return api.content.gettodos(payload.is) .then(response => { commit('SET_TODOS', response) return response }) .catch(error => { console.log(error) return error }) } - asanas
My own understanding of the problem is that the computed is already set before we even call the method. And at that time, the store doesn't have the data. Later on, the method is called and the store is filled. But I don't know how to correct it. - asanas
You could trigger the fetchData function from your root component (App.vue), so all other components can work with that data and use fetchData in the components to update the data. - Bennett Dams
For now, I've chosen to solve the problem by preponing where I call the fetchData() and the issue is temporarily resolved. However, I would like to keep the question open as I really intend to understand what's going on here. - asanas

2 Answers

1
votes

You could use following approach:

component.vue (and just render todoItem)

  methods: {
    async fetchData () {
      const _this = this;
      if (!this.$store.state.todos.hasOwnProperty(this.id)) {
        this.$store.dispatch('getToDos', {id: this.id, callback: () => {
          _this.todoItem = _this.$store.state.todos[_this.id]
        }});
      }
    }
  }

store.js

  actions: {
    getToDos: (context, payload) => {
      // simulate fetching externally 
      setTimeout(() => {
        context.commit("getToDos__", {newId: payload.id, task: "whatever" });
        payload.callback();
      }, 2000);
    },
-1
votes

I think what might solve it is if you create a getter for todos.

So in your VueX Store add:

getters: {
    todos(state) {
        return state.todos;
    }
};

And than in your computed use:

computed: {
    todos () {
        return this.$store.getters.todos[this.id]
    }
}