简体   繁体   English

Vue.js 3 和 Pinia Getters 的问题

[英]Problems with Vue.js 3 and Pinia Getters

I'm switching from Angular to Vue.js and trying to understand the architecture.我正在从 Angular 切换到 Vue.js 并试图了解架构。 I'm currently running into a fundamental problem and working with a lot of workarounds that I really only consider temporary solutions.我目前遇到了一个基本问题,并且使用了很多我实际上只考虑临时解决方案的解决方法。

The main issue here is the collaboration between Vue.js 3 and Pinia.这里的主要问题是 Vue.js 3 和 Pinia 之间的协作。 Pinia consists of the Store, Getters and Actions. Pinia 由 Store、Getters 和 Actions 组成。 Sometimes we have very nested objects in the Store and we only need certain parts of it.有时我们在 Store 中有非常嵌套的对象,我们只需要它的某些部分。 For that, it's perfect to create a getter, for example, to output only the parts of the object that I need.为此,创建一个吸气剂是完美的,例如,仅针对 output 我需要的 object 的部分。

But what if I want to change exactly those parts of the object from the template?但是,如果我想从模板中准确更改 object 的那些部分怎么办? My wish is that the data in the store changes as well.我希望商店中的数据也发生变化。 But since getters are readonly, this is not possible.但是由于 getter 是只读的,所以这是不可能的。

How would one proceed here?如何在这里进行?

Of course I would like to show you an example to underline my explanations with some practice.当然,我想向您展示一个例子,通过一些练习来强调我的解释。

export const useGeneralStore = defineStore('general', {
  state: () => {
    return {
      roles: [],
      currentRole: 'basic',
    }
  },
  getters: {
    getElementsForCurrentRole: (state) => {
      let role = state.roles.find((role) => {
        return role.value == state.currentRole;
      });

      if (role) {
        return role.data;
      }
    }
  },
  actions: {}
})

I am creating a store here with a very nested object roles .我正在这里创建一个具有非常嵌套的 object roles的商店。 In the getter getElementsForCurrentRole , which I use in the template for a v-for, I only need certain elements.在我在 v-for 模板中使用的 getter getElementsForCurrentRole中,我只需要某些元素。

To make it easier for you to understand, I'm also sending the template code here:为了方便大家理解,我也把模板代码发在这里:

<template>
  <div class="element-container">
    <div v-for="cat of elementCategories" :key="cat">
      <h4>{{cat}}</h4>
      <draggable 
        v-model="getElementsForCurrentRole" 
        :group="cat"
        @end="save" 
        item-key="name">
        <template #item="{element}">
          <n-card v-if="element.category == cat" class="element" :class="element.name" :title="element.name" size="small" header-style="{titleFontSizeSmall: 8px}" hoverable>
            <n-switch v-model:value="element.active" @update:value="save(element)" size="small" />
          </n-card>
        </template>
      </draggable>
    </div>
  </div>
</template>

<script setup>
  import { NCard, NSwitch, useMessage } from 'naive-ui';
  import draggable from 'vuedraggable'
  import { usePermissionsStore } from '@/stores/permissions';
  import { storeToRefs } from 'pinia';

  const permissionsStore = usePermissionsStore();
  const { getElementsForCurrentRole } = storeToRefs(permissionsStore);  

  const elementCategories = ['basic', 'professional'];
</script>

I loop through the getElementsForCurrentRole getter after using the storeToRefs function mentioned in the documentation to make the data reactive.在使用文档中提到的storeToRefs function 使数据具有反应性之后,我循环遍历getElementsForCurrentRole getter。 My problem here is that the data is probably only partially reactive.我的问题是数据可能只是部分反应。 For example, if I change the value of the Switch element, then the store updates successfully.例如,如果我更改Switch元素的值,则商店更新成功。 This works.这行得通。 However, I don't seem to have access to the order of the array I'm looping.但是,我似乎无法访问我正在循环的数组的顺序。 As soon as I change the order by drag and drop, I get the message: Write operation failed: computed value is readonly .一旦通过拖放更改顺序,我就会收到消息: Write operation failed: computed value is readonly

I don't understand this and I can't comprehend it.我不明白这一点,我无法理解。

As a workaround I currently calculate the old and the new index of the record in the array after dragging based on the event and update the store manually.作为一种解决方法,我目前根据事件计算拖动后数组中记录的旧索引和新索引,并手动更新存储。 But that can't be the purpose behind it.但这不能成为其背后的目的。 Have I fundamentally misunderstood something in the architecture?我是否从根本上误解了架构中的某些内容? How would one approach such a case?如何处理这种情况?

You're using a getter.你正在使用吸气剂。 Getters are readonly propreties.吸气剂是只读属性。 To update value in any pinia store you must create an action.要更新任何 pinia 商店中的值,您必须创建一个操作。 And you are using a v-model which binds and writes when the value changes.您正在使用 v-model,它在值更改时绑定并写入。 It can therefore read with the getter but not write.因此它可以用 getter 读取但不能写入。 In your case there are several possibilities.在您的情况下,有几种可能性。 one of them is to make a computed property and an action.其中之一是制作一个计算属性和一个动作。 like this像这样

actions: {
  updateRole(newRole) {
    this.currentRole = newRole
}

and the computed property in component:和组件中的计算属性:

const myComputed = computed({
  get: () => getElementsForCurrentRole.value,
  set: (val) => updateRole(val),
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM