【问题标题】:Component not updating when array changes数组更改时组件不更新
【发布时间】:2021-08-02 13:26:12
【问题描述】:

我是新手,所以也许这是设计使然,但以防万一。 我有一个组件,它采用 facets 列表,然后将它们拆分为一个漂亮的显示。 代码如下所示:

import { getFacets } from "@/logic/get-facets";
import {
  defineComponent,
  getCurrentInstance,
  ref,
  toRefs,
} from "@vue/composition-api";

import Filters from "@/components/filters/filters.component.vue";

export default defineComponent({
  name: "Chooser",
  components: { Filters },
  emits: ["onFilter"],
  props: {
    categoryName: {
      type: String,
      required: true,
    },
    facets: {
      type: Array,
      required: true,
    },
    loading: {
      type: Boolean,
      default: () => false,
    },
  },
  setup(props) {
    const instance = getCurrentInstance();
    const expanded = ref(false);
    const filters = ref([]);
    const scenarios = ref([]);
    const { facets } = toRefs(props);
    const { criteria } = getFacets(facets.value);

    const expand = () => {
      expanded.value = !expanded.value;
    };

    const addFilter = (attribute: any) => {
      let index = -1;
      for (let i = filters.value.length - 1; i >= 0; i--) {
        const filter = filters.value[i];
        if (filter.facetName !== attribute.facetName) continue;
        index = i;
        filters.value.splice(i, 1);
      }
      if (index === -1) filters.value.push(attribute);

      instance.proxy.$emit("onFilter", filters.value);
    };

    return { expanded, criteria, filters, scenarios, expand, addFilter };
  },
});

getFacets 方法如下所示:

import { ref } from "@vue/composition-api";

class Facet {
  key: string;
  value: FacetItem[];
}

class FacetItem {
  facetName: string;
  count: number;
  value: string;
  from: string;
  to: string;
}

export function getFacets(facets: any) {
  const criteria = ref([]);

  const facet = facets.find((item: Facet) => item.key === "Criteria/Attribute");

  let currentCriterionName = "";
  let criterion: any = {};
  let count = 0;
  (<Facet>facet).value
    .sort((a, b) => a.value.localeCompare(b.value))
    .forEach((item: FacetItem) => {
      const value = item.value;
      const [c, a] = value.split(":");

      if (c !== currentCriterionName) {
        if (criterion.name) criteria.value.push(criterion);

        criterion = {
          name: c,
          attributes: [],
          active: false,
        };

        currentCriterionName = c;
      }

      criterion.attributes.push({
        name: a,
        facetName: value,
        to: item.to,
        from: item.from,
        count: item.count,
      });
      count++;
    });

  if (count === facet.value.length) criteria.value.push(criterion);

  return { criteria };
}

如您所见,我的组件需要一个必需的 facets 数组(以及 categoryName 和可选的加载布尔值)。 初始数组如下所示:

[
  {
    "key":"Criteria/Attribute",
    "value":[
        {
          "count":5,
          "value":"Capacity:Extra Small",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":11,
          "value":"Capacity:Large",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":13,
          "value":"Capacity:Medium",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":19,
          "value":"Capacity:Small",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":8,
          "value":"Coffee at the press of a button?:Yes",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":13,
          "value":"Extraction Quality:Amazing",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":5,
          "value":"Extraction Quality:Exceptional",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":24,
          "value":"Extraction Quality:Good",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":6,
          "value":"Extraction Quality:Very Good",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":16,
          "value":"Milk Frother:Automatic",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":10,
          "value":"Milk Frother:None",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":22,
          "value":"Milk Frother:Steam Wand",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":10,
          "value":"Noise:Buzzing",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":10,
          "value":"Noise:Loud",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":23,
          "value":"Noise:Quiet",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":5,
          "value":"Noise:Silent",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":3,
          "value":"Size:Extra Small",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":6,
          "value":"Size:Large",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":31,
          "value":"Size:Medium",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":8,
          "value":"Size:Small",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":2,
          "value":"Speed:Instant",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":28,
          "value":"Speed:Quick Heat",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":5,
          "value":"Speed:Slow",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":13,
          "value":"Speed:Standard",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":7,
          "value":"Style:Designer",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":8,
          "value":"Style:Minimalist",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":20,
          "value":"Style:Modern",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":13,
          "value":"Style:Professional",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        }
    ],
    "__typename":"KeyValuePairOfStringAndListOfFacetModel"
  }
]

在这个组件中,当其中一个项目被点击时,它会执行一个返回一组新构面的搜索。以下是新数组的示例:

[
  {
    "key":"Criteria/Attribute",
    "value":[
        {
          "count":5,
          "value":"Capacity:Extra Small",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":5,
          "value":"Extraction Quality:Good",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":5,
          "value":"Milk Frother:None",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":5,
          "value":"Noise:Silent",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":5,
          "value":"Speed:Slow",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":5,
          "value":"Style:Minimalist",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":3,
          "value":"Size:Extra Small",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        },
        {
          "count":2,
          "value":"Size:Medium",
          "from":null,
          "to":null,
          "__typename":"FacetModel"
        }
    ],
    "__typename":"KeyValuePairOfStringAndListOfFacetModel"
  }
]

这一切都由父组件提供。初始数组是在页面加载时生成的,当点击上面的过滤器时,它会调用一个方法来更新 Chooser 组件使用的数组。

<chooser
  :categoryName="category.name"
  :facets="result.search.facets"
  :loading="loading"
  @onFilter="search($event)"
>
</chooser>

问题是,即使我可以在父组件中执行{{ result.search.facets }} 并看到数组更改,Chooser 仍然完全相同。 为了让 Chooser 在数组更改时更新,我必须做些什么吗?

【问题讨论】:

  • 你是在改变result.search.facets数组还是完全替换它?
  • criteria 应该是computed,所以每次fasets 属性更改时都会重建(通过执行getFacets 函数)。
  • 完全替换它

标签: vue.js binding


【解决方案1】:

不仅要更新数组,还要更新filters变量的链接。我认为问题在于 Vue 并不总是能检测到数组元素的变化。这是docs 中写的关于它的内容。

【讨论】:

    猜你喜欢
    • 2020-07-23
    • 1970-01-01
    • 1970-01-01
    • 2017-11-30
    • 1970-01-01
    • 2022-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多