【问题标题】:How to return a value from store (vuex) vuejs如何从商店(vuex)vuejs返回一个值
【发布时间】:2020-11-23 21:16:02
【问题描述】:

我正在做一个项目(只是个人)并尝试熟悉 vuex。我设法做了很多(到目前为止),但有一个坚果我无法破解。

我正在尝试访问一个字段 -> 特定员工的薪水

这是我的 store.js (vuex)

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

Vue.use(Vuex)

export const store = new Vuex.Store({
  state: {
      emps: [
              {name: 'John', salary: 110},
              {name: 'Jimmy', salary: 80}
      ],
  },
  getters: {
  },
  mutations: {
    getCurrentSalary: (state, data) => {
      var empIndex = findEmpIndex(data);
      console.log(state.emps[empIndex].salary); // this is ok!!
      return state.emps[empIndex].salary;
    }
  },
  actions: {
    getCurrentSalary: ({commit}, payload) => {
      commit('getCurrentSalary', payload);
    }
  }
});


// helpers
function findEmpIndex (stockName) {
   return store.state.markets.findIndex(item => item.name === stockName);
}

在特定员工的一个组件中,我这样称呼它:

<template lang="html">
  <div class="container">
     Current Salary: {{ getCurrentSalary("John") }}
  </div>
</template>

<script>
  import {mapActions} from 'vuex'

  export default {
      methods: {
        ...mapActions([
          'getCurrentSalary'
        ])
      }
  }
</script>

<style lang="css" scoped>
</style>

但是有一个问题是薪水可能会发生变化,所以我想立即获得变化(无论何时发生)

我可以正确看到控制台日志(这至少意味着正在调用该函数..但打印时显示:

Current Salary: [object Promise]

它不想打印值,而是打印一个承诺。我做了很多搜索,但没有找到(或者可能理解)如何解决这个问题……如果有任何类似的论坛或问题对此有解决方案的请发送链接(抱歉)

【问题讨论】:

    标签: vue.js vuex


    【解决方案1】:

    您似乎想获得 getCurrentSalary mutation 的返回值,但您在组件中调用了 getCurrentSalary action

    由于您尝试获取数据而不是更改数据,我建议您删除突变并创建一个 getter。

    类似:

      getters: {
        getCurrentSalary: (state) => (data) => {
          var empIndex = findEmpIndex(data);
          console.log(state.emps[empIndex].salary); // this is ok!!
          return state.emps[empIndex].salary;
        }
      },
    

    然后在您的组件中使用mapGetters 而不是mapActions

    【讨论】:

    • 我似乎无法完成这项工作 :( 我收到 Error in render: "TypeError: Cannot read property 'salary' of undefined"
    【解决方案2】:

    我只想说你的例子是人为的,它不会起作用。首先,在您的示例中,商店状态已经填充,除非调度获取工资数据的操作,否则情况不会如此。如果派发了获取薪水数据的操作,您将不需要获取每个用户的当前工资的操作,因为这是从商店获取数据的问题。

    话虽如此,如果您的示例“正确”,我将引导您完成使用 Vuex 商店的过程。

    在您的模板中,您想要的是在创建或安装组件时调度一个操作(使用createdmounted 挂钩)。我偏爱安装的挂钩,所以我会使用它,

    EmployeeComponent.vue

    <script>
      import {mapActions} from 'vuex'
    
    export default {
      methods: {
        ...mapActions([
          'getEmployeeSalaries'
        ])
      },
      mounted() {
        this.getEmployeeSalaries(); // dispatch action when component mounts. You want to get the updated salary of employees
      }
     }
    </script>

    然后您继续在操作中提交突变(就像您所做的那样)。您根据 Vuex documentation 更改突变状态是正确的,

    在 Vuex 存储中真正改变状态的唯一方法是提交 一个突变。

    Vuex 存储就像组件中的 data 属性一样具有反应性,因此如果状态发生变化,具有该状态的模板部分会重新呈现。

    有两种获取状态数据的方法。

    • 获取模板中的状态。您可以使用mapStatethis.$store.state 访问模板中的状态。然后在计算属性中,更改状态并将其返回(如有必要)。您需要更改状态,因为您没有返回员工数组的完整状态,而是返回一名员工的薪水。 (以下示例来自文档)

    import { mapState } from 'vuex';
    
    computed: {
      ...mapState({
        // map this.count to store.state.count
        'count'
      }),
      doneTodosCount () {
        return this.$store.state.todos.filter(todo => todo.done).length
      }
    }

    不过,就像documentation 状态一样,更改组件中的存储状态(使用 this.$store.state.. 或使用 mapState 然后更改它)并不理想,因为:

    如果有多个组件需要使用它,我们必须 要么复制函数,要么将其提取到共享帮助器中,然后 在多个地方导入它 - 两者都不太理想。

    这让我想到了第二种获得改变状态的方式

    • 您可以在 store 中使用 getter,然后在模板中使用 mapGetters 访问它们。 Getter 是理想的选择,因为正如文档所述:

    您可以将它们视为商店的计算属性。像计算属性一样,一个 getter 的结果是根据其依赖关系缓存的,并且只会 重新评估它的一些依赖关系何时发生变化。*

    使用 getter(在本例中为当前薪水 getter),您可以在应用程序的其他任何地方使用它,而无需重复或将其转换为辅助函数并多次导入(如文档中所述)。

    Vuex 商店

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    
    export const store = new Vuex.Store({
      state: {
        emps: [], // the state should be empty. The store cannot be populated without a mutation
      },
      getters: {
        currentSalaryOfUser: state => {  // this won't work in your example because store state is not being changed. The getter will only change when state.emps state changes. Just like a computed property in the vue instance.
          var empIndex = findEmpIndex(data);
          return state.emps[empIndex].salary; // you return the "altered" state (just the salary, instead of the whole state. If you are returning the whole state, it will be better to use mapState or this.$store.state to get the data.) which can be used in multiple cases if required, without duplication, as stated in the docs.
        }
      },
      mutations: {
        getCurrentSalary (state, payload) {
          // There is no state to mutate in your case. You are trying to get a salary state which is already updated by the getEmployeeSalaries action and mutation.
        },
        getEmployeeSalaries(state, payload) {
          // mutate state
          state.emps = payload; // this is what should happen. The employee salaries should be obtained in an action called getEmployeeSalaries (or any data you give it). Your example is contrived so it won't work.
        }
      }
      actions: {
        getCurrentSalary: ({commit}, payload) => {
          commit('getCurrentSalary', payload); // this is redundant in your case. You don't need it. If the example were a good one, you will just get the data from your state which is populated by the getEmployeeSalaries action and mutation
        },
        getEmployeeSalaries: async ({commit}) => { // there should be an action like this that is dispatched from your template. This will probably be an asynchronous action that gets data from the database
    
          const response = await databaseCallToFetchData; // wait for the data to be fetched from the database
          const payload = response.data.data // get the payload from the database call
          commit('getEmployeeSalaries', payload);
        }
      }
    });

    然后在你的模板中:

    EmployeeComponent.vue

    import { mapGetters } from 'vuex'
    
    export default {
      computed: {
        // mix the getters into computed with object spread operator
        ...mapGetters([
           'currentSalaryOfUser' // changed the name to avoid a clash with the getCurrentSalary action
        ])
      }
    }

    <template lang="html">
      <div class="container">
         Current Salary: {{ currentSalaryOfUser }}
      </div>
    </template>

    【讨论】:

    • 你好,谢谢你的“文章”......我真的很感激......我无法让你的解决方案工作......并且有一个问题 -> 我需要通过一个论点到那个功能,因为我只想为特定员工获得薪水......另一个问题是,薪水可以改变(我的应用程序中有一个按钮),它“增加薪水”......因此,我想要获取当前的(无论是否在开始时填充 - 这只是一个演示)
    • 嗨,@Mr.P,我想告诉你的是你的解决方案无法工作。它无法工作的原因是因为您正在改变状态。商店里的数据如何获取?
    【解决方案3】:

    我已经用 getter 解决了 :) 唯一的技巧是返回一个值(基于传递的参数)是在 getter 中返回一个函数 :)

    getters: {
        getSalary: (state, getters) => (empName) => {
          var empIndex = findEmpIndex(empName);
          return state.emps[empIndex].salary;
        }
      }
    

    并按如下方式调用它(在组件中):

    <template lang="html">
      <div class="container">
          Current Value: {{ getSalary(emps.name) }} 
      </div>
    </template>
    
    <script>
      import {mapGetters} from 'vuex'
    
      export default {
          computed: {
            ...mapGetters([
              'getSalary'
            ])
          }
      }
    </script>
    

    它会在线/实时对工资的变化做出反应:)

    谢谢大家

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-19
      • 2022-01-03
      • 1970-01-01
      • 2019-02-27
      • 2018-12-21
      • 2020-12-12
      • 2018-07-12
      • 1970-01-01
      相关资源
      最近更新 更多