Observe Complex Objects — Date Example

DEX475 - Fields, Properties, and Attributes

📄 第 109 页 🎬 视频课程

课程章节介绍

同学们,咱们今天聊聊Lightning Web Components里一个比较特别的细节,就是关于Date、Set和Map这种复杂对象的响应式追踪问题。 你们可能已经知道,在LWC里,用@track装饰符可以让LWC引擎追踪一个属性的变化,只要属性值变了,组件就会自动重新渲染。但这里有个特例,即使你写了@track,如果这个属性的值是Date、Set或者Map这些复杂对象,引擎是不会观察到它们内部状态变化的。为什么呢?因为它们不是普普通通的JavaScript对象,它们是继承了自己特有的原型的,像是Date.prototype、Set.prototype这些。引擎的观察机制只关注属性引用的变化,它并不深入对象内部去监视。 咱们用个具体点的例子来说明。假设咱们模板里有一个属性叫x,它的值是一个Date对象。页面上有两个按钮,一个Init,一个Update。当你点Init按钮的时候,代码里会新建一个Date对象,然后把它赋值给this.x。这时候x的引用变了,从旧对象变成了全新的对象,所以LWC能检测到这个变化,重新渲染就发生了。 但当你点击Update按钮的时候,代码可能写的是this.x.setHours(7),直接调用了Date对象自己的方法,去修改它的内部小时数。注意,这个操作只改变了对象内部的状态,x变量指向的还是原来那个Date对象,引用根本没变。LWC引擎没有它内部改动的通知,所以就无动于衷,不会重新渲染。你可能觉得自己改了时间,页面上怎么没反应呢? 这时候,如果你打开浏览器的开发者工具控制台,它其实会给出一个挺友好的警告。大概内容是,属性x被设置成了一个“不可追踪的对象”,意思就是LWC没法看到这个对象内部的变化。然后它会建议你,在对对象做内部修改之前,先克隆一下这个对象。 所以,碰到这种需求,咱们该怎么做呢?解决思路很简单,就是不要直接在原对象上动手脚。你可以在修改前,先克隆一份,比如用new Date(this.x.getTime())来创建一个新的Date对象,然后在这个新对象上做setHours(7)之类的操作,最后把新对象赋给this.x。这样引用就变了,引擎就能捕捉到,重新渲染就会触发。对于Set和Map也是类似的道理,先创建新的集合,操作完再赋值。 总结一下:@track是监视属性引用的,Date、Set、Map这些对象内部变化它看不见。要让它生效,你就得通过改变对象的引用来触发,最常用的办法就是先克隆,再修改,再赋值。 好了,这个小知识点就讲到这里,希望你们以后写代码时遇到这种“改了没反应”的情况,能第一时间想到是这个原因。

关键词

LWC Lightning Web Components Salesforce