具有对象文字作为道具的 Vue.js 子组件在其父组件呈现时意外更新

myl*_*ore 2 javascript vue.js

我有几个 Vue 组件传递了一些对象文字作为道具,例如

<child :prop1="{ foo: 'bar' }"></child>
Run Code Online (Sandbox Code Playgroud)

但是,当父组件重新渲染时,如下面的最小代码和框示例所示,prop1更改(由观察者检测)并导致Child更新。如果 prop 是一个对象引用,它保持不变。

为什么会发生这种情况,这是否意味着使用对象字面量(可能还有数组字面量)作为道具可能不“安全”?

https://codesandbox.io/s/vue-template-jj0tb

ski*_*tle 5

每次模板运行时,它都会在遇到该部分时创建一个新对象。这同样适用于任何引用类型,因此数组、函数等。

它类似于在 JavaScript 代码中创建的对象等。例如

function getObject() {
    return {};
}

console.log(getObject() === getObject()); // false
Run Code Online (Sandbox Code Playgroud)

每次getObject调用它都会返回一个新对象,对象相等性基于引用而不是对象是否包含相同的值。这实际上是 Vue 在检查更改的 props 时所做的。请记住,Vue 模板被编译为一个render函数,而这只是普通的 JavaScript。任何对象文字仍将是该render函数中的对象文字。

在您的示例中,父级的渲染函数看起来像这样,假设模板中没有其他内容:

function render(h) {
    return h('child', {
        props: {
            prop1: {foo: 'bar'}
        }
    })
}
Run Code Online (Sandbox Code Playgroud)

所以每次运行时都会有一个新的对象prop1

正如您已经提到的,将对象移动到您的对象data然后按名称引用它可以确保每次都使用相同的对象,从而避免子更新。

是否值得担心取决于您的场景的具体情况,但如果有足够多的孩子像这样更新,它可能会对性能产生影响。子渲染不应该需要更新实际的 DOM,但如果它们依赖于该 prop,任何计算属性、监视或模板都将运行。