Vue3 Treelist 中的反应式 props 会导致递归更新

问题描述 投票:0回答:1

我目前在我的项目中使用 vue3-tree 并尝试配置节点,我使用 pinia 将 props.filter.data 存储到父级,但我不断收到此错误:

未捕获(承诺)超出最大递归更新数。这意味着您有一个反应效应,它会改变其自身的依赖关系,从而递归地触发自身。可能的来源包括组件模板、渲染函数、更新的钩子或观察者源函数。

我的组件目前看起来像这样:

<template>
  <div data-cy="filter-tree-list">
    <tree
      data-cy="filter-tree-list-component"
      data-test="filter-tree-list"
      class="flex flex-row w-full justify-start items-stretch rounded-md px-3 py-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300"
      v-if="props.filter.data"
      rowHoverBackground="#b2ffff40"
      :nodes="props.filter.data"
      :use-checkbox="true"
      @update:nodes="onUpdate"
      @nodeClick="onNodeClick"
    >
    </tree>
  </div>
</template>
    
<script setup lang="ts">
    import { inject, defineEmits, defineProps, ref, watch } from "vue";
    import { Filter } from "../../types/common/filter";
    
    interface Node {
      id: string;
      label: string;
      nodes: Array<Node>;
      checked?: boolean;
    }
    
    const piniaRef: unknown = inject("piniaStore");
    
    const props = defineProps({
      filter: {
        type: Object as () => Filter,
        required: true,
      },
      isReadOnly: {
        type: Boolean,
        default: false,
      },
    });
    
    const emit = defineEmits(["filterChange"]);
    const changed = ref(false);
    const checkedIds = ref<string[]>([]);
    
    const filterValueHasChanged = () => {
      if (props.filter.value === "") {
        clearCheckedIds(props.filter.data as unknown as Node[]);
      }
    };
    
    watch(() => props.filter.value, filterValueHasChanged);
    
    const onUpdate = (nodes: Node[]) => {
      if (piniaRef && props.filter.value === undefined) return;
    
      checkedIds.value = [];
      getCheckedIds(nodes);
    
      //vue 3 doesnt recommend changing v-model values as props, disable warning until fixed
      // eslint-disable-next-line
      props.filter.value =
        checkedIds.value.length > 0 ? checkedIds.value.join(",") : "";
      filterHasChanged();
    
      if (piniaRef && props.filter.immediate) {
        emitFilterChange();
      }
    };
    
    const onNodeClick = (node: Node) => {
      const checked = node.checked;
      if (Array.isArray(node.nodes)) {
        node.nodes.forEach((childNode) => {
          childNode.checked = checked;
        });
      }
    };
    
    const getCheckedIds = (nodes: Node[]) => {
      if (Array.isArray(nodes)) {
        nodes.forEach((node) => {
          if (Array.isArray(node.nodes)) {
            getCheckedIds(node.nodes);
          } else if (node.checked) {
            checkedIds.value.push(node.id);
          }
        });
      }
    };
    
    const clearCheckedIds = (nodes: Node[]) => {
      if (Array.isArray(nodes)) {
        nodes.forEach((node) => {
          node.checked = false;
          if (Array.isArray(node.nodes)) {
            clearCheckedIds(node.nodes);
          }
        });
      }
    };
    
    const filterHasChanged = () => {
      changed.value = true;
    };
    
    const emitFilterChange = () => {
      if (changed.value) {
        emit("filterChange", props.filter);
        changed.value = false;
      }
    };
</script>

此错误在生产中不断中断,导致无限重新渲染,但在开发中运行良好。我尝试将 props 放入 ref 和计算方法中,但无济于事。

非常感谢任何帮助。

vue.js vuejs3 treeview nodes pinia
1个回答
0
投票

我决定使用 PrimeVue treeSelect,因为 vue3-tree 库已从根本上损坏并且与最新版本的 vue 3 不兼容。 该组件允许选择和取消选择道具,这允许我选择键并将其添加到空数组中:

<template>
    <div class="card flex justify-content-center">
        <TreeSelect 
             v-model="selectedValue" 
            :options="nodes" 
            selectionMode="checkbox" 
            placeholder="Select Item" 
            class="md:w-20rem w-full" 
            @nodeSelect="onNodeSelect"
            @nodeUnselect="onNodeUnselect"
            />
    </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import { NodeService } from './service/NodeService';

const nodes = ref(null);
const selectedValue = ref(null);
const selectedIds = ref([])

onMounted(() => {
    NodeService.getTreeNodes().then((data) => (nodes.value = data));
});

const onNodeSelect = (node) => {
console.log('selected', node.key)
selectedIds.value.push(node.key)
console.log(selectedIds.value)
}

const onNodeUnselect = (node) => {
 let unselectedId = node.key
 console.log('unselectedId: ' , unselectedId)
 selectedIds.value = selectedIds.value.filter(key => key !== unselectedId);
 console.log(selectedIds.value)
}
</script>
© www.soinside.com 2019 - 2024. All rights reserved.