【问题标题】:Helper function in VuexVuex 中的辅助函数
【发布时间】:2020-10-01 08:52:34
【问题描述】:

我是 Vuejs 的新手,但我来自 React,只是想在这里使用 Vuex。

我使用包含数组cart 的状态构建了我的商店。

const state = () => ({
    cart: []
})

我想要一个函数 isInCart(product) 来返回产品是否在当前购物车中。

<span v-if="isInCart(product)">hello</span>

我应该使用商店的 getters 吗?

const getters = {
    isInCart: (state) => (product) => state.cart.find(_product => _product.id === product.id) !== undefined,
}

然后在我的组件中像这样使用它?

computed: {
    ...mapGetters(['isInCart'])
},

但我有:Computed property "isInCart" was assigned to but it has no setter.

编辑

我忘了在 getter 前面加上它的模块名称。

...mapGetters({ isInCart: 'shop/isInCart' }) // module name = shop

【问题讨论】:

    标签: vue.js vuejs2 vuex


    【解决方案1】:

    Ref:我应该使用我商店的 getters 吗?

    是的。 ...mapGetters({}) 仅从您的商店中读取 getter

    如果您想读取 state 属性(即:cart),请使用

    computed: {
      ...mapState({ cart })
    }
    

    ...或

    computed: {
      cart() {
        return this.$store.state.cart
      }
    }
    

    参考:Computed property "isInCart" was assigned to but it has no setter.

    这是因为您试图在要导入它的组件内为 isInCart 分配一个值。

    你不能那样做。如果您想实际将 store getter 设置为特定值,请使用以下模式:

    computed: {
      yourGetter: {
        get: function() {
          return this.$store.getters['yourGetter']
        },
        set: function(value) {
          this.$store.dispatch('actionCommittingMutationChangingYourGetter', value)
        }
      }
    }
    

    注意:如果您只需要此组件中的 getter,则不必是 store getter。你可以直接从stateget它:

    computed: {
      whatever: {
        get: function() {
          return this.$store.state.whatever;
        },
        set: function(value) {
          this.$store.dispatch('setWhatever', value);
        }
      }
    }
    

    注意:如果您的 getter 返回一个函数(如您的情况),您可以在将其映射到组件中后安全地调用它:(即:this.isInCart(product))。使用带参数的计算是不常见的,但如果它返回一个 fn,则可以调用 fn。

    另一方面,在许多情况下,您可以直接跳过dispatchcommit。但是直接从商店外部提交并不被认为是“安全的”,在某些情况下,您会因为这样做而出错。
    出于原则,我建议不要这样做,尽管它在某些情况下确实有效。


    参考如何编写你的 fn 清理器。此讨论涉及很多个人偏好以及您或您的团队可能制定的编码标准。这使得讨论 per-se 在 Stack Overflow 上脱离了主题。

    只是为了好玩,这就是我的写作方式。但这并不是因为它更好或更清洁。它完全基于个人喜好,它可能比你拥有的要快一点点:

    const getters = {
      isInCart: state => product => state.cart.map(p => p.id) 
        .findIndex(id => id === product.id) > -1
    }
    

    【讨论】:

    • 您的回答充满了很好的内容,但并没有真正回答我关于如何构建isInCart(product) 函数清理器的问题。
    • @robinvrd,首先,“如何编写函数清理器?” 在 SO 上是题外话。这可能是code review 上的一个好问题。另一个问题是您要问的问题不止一个。上面的一个和一个关于错误的。最后但并非最不重要的一点是,您没有包含产生错误的代码(如果我只使用您的代码,我不会收到该错误)。尽管有上述所有理由将问题关闭为题外话,但我试图通过提供有用的见解来提供帮助。考虑到当前的问题状态,不知道我该如何提供更多帮助。
    • 提供minimal reproducible example,我会看看。如果您需要基于多文件节点的环境,请使用 codesanbox.io 或类似文件。
    • 我的错误是没有在我的 getter 前面加上它的模块......只有新手才能做的蠢事。
    • 发生在我们所有人身上。出于某种原因,人们希望有经验的开发人员不要犯愚蠢的错误。它一直在发生。只是您使用了更多工具来尽早发现它们。我想说,这是唯一的区别。
    【解决方案2】:

    看看这个带有参数的 Vuex getter 的答案:Pass params to mapGetters

    编辑

    我同意,它不干净也不简单。我宁愿重新设计这个:

    选项 1

    您可以使用 Vuex 的购物车并直接计算,保持反应性:

    <template>
      <span v-if="$store.state.cart.some(p => p.sku === productSku)">hello</span>
      <!—- both work efficiently —>
      <span v-if="hasProduct(productSku)">hello</span>
    
    </template>
    <script>
    export default {
      methods: {
        hasProduct(sku) {
          return this.$store.state.cart.some(p => p.sku === sku)
        }
      }
    }
    </script>
    

    话虽如此,这不是计算属性。您希望计算属性有多个返回值,但它不是为此目的而设计的。

    选项 2

    您最好的选择是引入此组件的产品相关版本:

    <template>
      <span v-if="hasProduct">hello</span>
    <template>
    
    <script>
    export default {
      name: „ProductRelevantComponent“
      props: {
        productSku: {
          type: String,
          required: true
        }
      },
      computed: {
        hasProduct() {
          return this.$store.state.cart.some(p => p.sku === this.productSku)
        }
      }
    }
    </script>
    

    【讨论】:

    • 看起来一点也不干净、轻巧和简单,还有其他提示吗?
    • 我为你添加了两个选项
    • 我最终让它作为我的组件的一种方法,尽管它可以做得更干净......
    猜你喜欢
    • 2019-01-17
    • 2017-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-04
    • 1970-01-01
    • 2014-01-23
    相关资源
    最近更新 更多