Set a Non-Primitive Value — Child Side & Mutation Rules

DEX475 - Composition

📄 第 72 页 🎬 视频课程

课程章节介绍

我们现在来深入聊聊一个在LWC构图中超级重要的模式,它可能会让你在刚开始接触组件通信时感到有点困惑,但搞懂之后就一通百通了。 想象一下,你有一个父组件,把一个对象传给了子组件。子组件通过 `@api obj` 来接收这个对象,然后在界面上显示它的某个属性,比如 `obj.msg`。接着,你在子组件里放两个按钮,一个叫“更新原始”,一个叫“更新浅”。当你点击“更新原始”时,代码试图直接修改 `this.obj.msg`,比如把它改成 `this.obj.msg + ’!’`。结果呢?浏览器控制台马上会甩给你一个错误,上面写着“无效变异”。这是为什么呢? 因为在LWC里,从父组件传递过来的非原始类型的值,比如对象和数组,会被自动包装成一个只读的代理。你可以把它想象成外面套了一层透明的防护罩,你可以读取它,但不能直接更改它内部的嵌套属性。所以,想通过 `this.obj.msg = ...` 这种方式去修改,是行不通的。这是为了强制单向数据流,保证数据的变化是可追踪的。 那我们想要更新这个对象该怎么办呢?这就是“更新浅”按钮要做的事。它的做法是使用展开运算符,创建一个新的对象副本,像这样:`{...this.obj, msg: this.obj.msg + ’!’}`,然后把这个新对象重新赋值给 `this.obj`。因为你现在是替换了整个对象的引用,而不是修改原有对象的内部属性,所以完全没问题,框架允许。 但是,这里藏着一个很容易踩的坑,也是一种非常重要的理解:你这种做法,仅仅是在子组件内部创建了一个浅拷贝,并且只更新了子组件自己的副本。父组件手上持有的那个原始对象,并没有发生任何改变。也就是说,子组件的视图看着变了,可父组件那边还是老样子。这通常不是我们想要的效果,因为如果父组件还要依据这个数据做别的逻辑判断,就会出现不一致的状况。 所以,正确的、完整的协作流程应该是:如果子组件需要让父组件也知道这个变化,那么子组件在本地更新完副本后,必须派发一个自定义事件,把修改后的数据传出去。父组件监听这个事件,拿到新数据后,用它去更新自己数据源里的那份原始对象。这样,两端就同步了,整个数据流动也是清晰、可控的。 简单总结一下:不能直接突变父组件传下来的对象属性;要先拷贝再替换;浅拷贝只是本地更新,要同步给父组件,必须通过事件。这就是LWC里处理对象传递的核心模式,希望你以后在设计组件时,心里一直记着这条流水线。

关键词

LWC Lightning Web Components Salesforce