reactive props in Vue3 Treelist causes recursive updates

27 Views Asked by At

I am curently using vue3-tree for my project and im trying to configure the nodes, im using pinia to store props.filter.data up to the parent, but i keep getting this error:

Uncaught (in promise) Maximum recursive updates exceeded. This means you have a reactive effect that is mutating its own dependencies and thus recursively triggering itself. Possible sources include component template, render function, updated hook or watcher source function.

My component currently looks like this:

<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>

This error keeps breaking in production causing an infinite rerender, but works fine in development. I have tried putting the props in a ref and in a computed method, but to no avail.

Any helps is greatly appreciated.

0

There are 0 best solutions below