为什么我的方法由于未知原因而被调用?

时间:2019-06-17 14:09:24

标签: vue.js

我具有函数filterData,该函数根据多个输入来更新图表数据。但是,如果更改了不相关的输入(例如在文本字段中键入内容),则每次都会调用该函数,从而导致图表重新呈现。我已经记录了输出,并且所有参数都没有更改。

为什么调用该函数?反正有跟踪还是我做错了?

<DeviceChart :input-data="filterData(inputData, filters, otherParams)"/>
export default {
  methods: {
    filterData(inputData, inputFilters, otherParameters) {
      console.log('Filter data has been called...')
      ...
      return result;
    }
  }
}

1 个答案:

答案 0 :(得分:2)

首先,有一点背景。

Vue模板将被编译为render函数。组件呈现时,将调用此函数,并且它将返回VDOM节点树。这些VDOM节点描述了子组件和相应的DOM。当组件随后更新此render函数时,将再次调用,返回新的VDOM树。然后Vue比较旧树和新树,并决定要进行哪些更改。

您可以认为render函数与计算属性非常相似。返回类型,一棵VDOM节点树,可能对您有点陌生,但除此之外,它就像您可能自己编写的任何计算属性一样。它运行,跟踪依赖关系并返回一个值。如果这些依赖项随后发生更改,它将再次运行。

重要的是,就像具有计算属性一样,Vue对如何在该函数中使用依赖项也不具有详细的知识。对依赖项的任何更改都将导致整个render函数重新运行。

这听起来可能很昂贵,但通常开销并不大。比较VDOM节点的树通常也很便宜。昂贵的部分是更新DOM,无论使用哪种方法,您都必须这样做。

因此,当您谈论“不相关的输入”更改时,需要记住,模板(即render函数)将始终作为一个整体运行。如果任何依赖项发生更改,则模板中的所有代码将重新运行。

在您的情况下,您有一个方法调用来过滤input-data的值。每次模板运行时都会调用该方法。输入和图表可能是模板中的独立组件,但没关系,整个模板都需要运行以生成新的VDOM树。输入后的数据是模板的依赖项,并且当它更改时(由于输入而导致的结果),模板将重新运行。

但是,子组件不一定会重新渲染。当Vue比较父组件节点的VDOM树时,它会尝试将旧树和新树中的子节点配对(这就是key的作用,以提示要配对的子节点)。与孩子配对后,它将为需要它的任何孩子更新道具。如果孩子的道具没有改变,则该孩子不需要重新渲染自己。

在您的情况下,我假设input-data是一个数组。每次调用方法filterData时,它将返回一个新数组。就您而言,该数组可能“相同”,但实际上并非相同。从JavaScript ===的角度来看,值已更改。我不确定DeviceChart对这些数据的处理方式,但这很可能是导致其重新呈现的原因。对于Vue组件,重新渲染是一个便宜的过程,通常不值得担心,但是您的图表可能正在使用某些第三方库,并且重新渲染可能并不那么简单。

最简单的解决方案可能只是对input-data使用计算属性。由于缓存了计算的属性,因此每次模板运行时,您将获得相同的数组。仅当计算函数的依赖关系发生更改时,缓存才会失效,因此模板的其他依赖关系将不起作用。

有很多选择,其中大多数都很痛苦。通常,这些操作涉及将过滤后的值存储在data中,并在需要时尝试对其进行更新。如果可以帮助,我不建议您尝试类似的事情。

如果有一个循环,计算的属性会变得很奇怪。

一种可行的替代方法也可以很好地与循环配合使用,即为图表引入包装器组件。如果将inputDatafiltersotherParams作为3个单独的道具传递给该包装器组件,则可以将执行实际过滤的职责移到包装器组件中。只要这3个道具不改变,当外部模板重新渲染时,包装器就不会重新渲染。我仍然建议在包装器中使用计算属性,但这无关紧要,因为无论如何该模板都不会运行。