【问题标题】:How to use vuex getter after async api call异步api调用后如何使用vuex getter
【发布时间】:2019-05-15 13:53:44
【问题描述】:

在您调度了一个改变状态的异步操作后,在 vuex 中调用 getter 的正确方法是什么?

我创建了一个示例 sn-p 来说明我的意思。如您所见,getLastNameByName() 失败,因为state.persons 为空。奇怪的是,如果我在那个 getter 中打印 state.persons,它会在 api 调用之后打印数组。

预期的行为是 getLastNameByName('John') 返回 {name: 'John', lastname: 'Smith'}

const store = new Vuex.Store({
  state: {
    persons: []
  },

  getters: {
    getLastNameByName: (state) => (name) => {

      // console.log(state.persons) returns the state, yet I cannot call .find on it 
      return state.persons.find(element => {
        return element.name === name
      }).lastname
    },
  },

  mutations: {
    setPersons: (state, payload) => {
      state.persons = [...payload]
    }
  },

  actions: {
    async getPeople({commit}) {
        return new Promise(function(resolve, reject) {
          setTimeout(async () => {
             commit('setPersons', [{
               name: 'John',
               lastname: 'Smith'
            }, {
            name: 'Sarah',
            account: 'Appleseed'
          }])

           resolve();
         }, 1000)
      })
  }
  }
})

new Vue({
  store,
  el: '#app',
  mounted() {
    this.$store.dispatch('getPeople').then( () =>  { 
      console.log(this.$store.getters.getLastNameByName('John'))
    })
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vuex"></script>

<div id="app">
</div>

【问题讨论】:

    标签: asynchronous vue.js async-await state vuex


    【解决方案1】:

    setTimeout() 不返回等待对象。检查承诺:

    const store = new Vuex.Store({
      state: {
        persons: []
      },
    
      getters: {
        getLastNameByName: (state) => (name) => {
          return state.persons.find(element => {
            return element.name === name
          }).lastname
        },
      },
    
      mutations: {
        setPersons: (state, payload) => {
          state.persons = [...payload]
        }
      },
    
      actions: {
        async getPeople({commit}) {
            return new Promise(function(resolve, reject) {
              setTimeout(async () => {
                 commit('setPersons', [{
                   name: 'John',
                   lastname: 'Smith'
                }, {
                name: 'Sarah',
                account: 'Appleseed'
              }])
    
               resolve();
             }, 1000)
          })
        }
      }
    })
    
    new Vue({
      store,
      el: '#app',
      mounted() {
        this.$store.dispatch('getPeople').then(() => {
           console.log(this.$store.getters.getLastNameByName('John'));
        })
      } 
    })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    <script src="https://unpkg.com/vuex"></script>
    
    <div id="app">
    </div>

    无论如何,直接处理对存储的异步调用不是正确的方法。我认为在这种情况下更好的解决方案是watch 存储状态或使用computed 属性。

    【讨论】:

    • 我的错,我以为我以这种方式正确地重现了我的问题。该示例现在确实可以正常工作,所以我想这是因为我的项目中的其他内容。您能否详细说明您建议的更好的解决方案?在state.persons 上设置一个观察者并调用该手表中的吸气剂?但是,问题是我需要在另一个操作中使用该 getter。
    【解决方案2】:

    在 jsbin.com 上试过,改进很少,没问题:

    <!DOCTYPE html>
    
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>Vue example</title>
    
    <div id="app">
      <show-person
        :name="getLastName('John')"
      ></show-person>
    </div>
    
    <script src="https://unpkg.com/vue@2.5.21/dist/vue.min.js"></script>
    <script src="https://unpkg.com/vuex@3.0.1/dist/vuex.min.js"></script>
    
    <script>
    const store = new Vuex.Store({
      state: {
        persons: []
      },
    
      getters: {
        getLastName: state => name => {
          return state.persons.length
            ? state.persons.find(element => {
                return element.name === name
              }).lastname
            : ''
        }
      },
    
      mutations: {
        setPersons: (state, payload) => {
          state.persons = [...payload]
        }
      },
    
      actions: {
        getPeople: ({ commit }) => new Promise(res => {
          const data = [
            {name: 'John', lastname: 'Smith'},
            {name: 'Sarah', account: 'Appleseed'}
          ]
          setTimeout(() => {
            commit('setPersons', data)
            res()
          }, 1000)
        })
      }
    })
    
    const ShowPerson = {
      functional: true,
      render: (h, ctx) => h('p', ctx.props.name)
    }
    
    new Vue({
      store,
      el: '#app',
    
      components: {
        ShowPerson
      },
    
      computed: {
        ...Vuex.mapGetters([
          'getLastName'
        ])
      },
    
      methods: {
        ...Vuex.mapActions([
          'getPeople'
        ])
      },
    
      created () {
        this.getPeople()
      }
    })
    </script>
    

    【讨论】:

      猜你喜欢
      • 2017-03-17
      • 2019-08-21
      • 2020-05-17
      • 2018-02-22
      • 2018-02-09
      • 2011-09-29
      • 2020-05-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多