[英]How to force an update of a subcomponent?
Lit Documentation says:点燃的文档说:
When called with no arguments,
requestUpdate()
schedules an update, without calling ahasChanged()
function.当在没有 arguments 的情况下调用时,requestUpdate()
会安排更新,而不调用 hasChangedhasChanged()
function。 But note thatrequestUpdate()
only causes the current component to update.但请注意requestUpdate()
只会导致当前组件更新。 That is, if a component uses the code shown above, and the component passesthis.myArray
to a subcomponent, the subcomponent will detect that the array reference hasn't changed, so it won't update.也就是说,如果一个组件使用上面显示的代码,并且该组件将this.myArray
传递给一个子组件,则该子组件会检测到数组引用没有改变,因此它不会更新。
So how to force an update of a subcomponent (even if the subcomponent's attribute doesn't change)?那么如何强制更新子组件(即使子组件的属性没有改变)?
render() {
return html`
<ul>
${this.myArray.map(
(item) => html`
<li>
${item.text}
<my-subcomponent foo="${item.bar}"></my-subcomponent>
</li>
`
)}
</ul>
`;
}
Edit: Repro in Lit Playground编辑: 灯光游乐场中的重现
创建this.myArray
的克隆以强制子组件重新渲染
this.myArray = [...this.myArray]
Thank you for the lit.dev playground repro, I was able to identify some issues that should resolve your issue.感谢您提供 lit.dev 游乐场重现,我能够确定一些应该解决您的问题的问题。
Before jumping into the various fixes, why is the subcomponent not re-rendering?在进行各种修复之前,为什么不重新渲染子组件? LitElements render as a function of their properties & state. LitElements 呈现为 function 和 state。 If properties don't change, they don't re-render.如果属性没有改变,它们就不会重新渲染。
The subcomponent has two reactive properties, myArray
and id
.子组件有两个反应属性, myArray
和id
。 myArray
is only set once on construction from localstorage and never updated - so it will never trigger an update. myArray
仅在从 localstorage 构造时设置一次并且从不更新 - 所以它永远不会触发更新。 The id
number also never changes for a given subcomponent so will never trigger an update.给定子组件的id
编号也永远不会更改,因此永远不会触发更新。 Because neither properties change, the subcomponent doesn't re-render.因为两个属性都没有改变,所以子组件不会重新渲染。
Fix 1 in Lit Playground 修复 1 照明游乐场
The only change I've made is to pass myArray
to sub-component
explicitly, (note .myArray=${this.myArray}
):我所做的唯一更改是将myArray
显式传递给sub-component
(注意.myArray=${this.myArray}
):
<li>${item.text} (<sub-component id=${item.id}.myArray=${this.myArray}></sub-component>)</li>
This works because now when the parent updates this.myArray
, the parent passes this new array to the sub-component.这是有效的,因为现在当父级更新this.myArray
时,父级将这个新数组传递给子组件。 The sub-component then notices that the reactive property myArray
has changed and a render is scheduled.然后,子组件会注意到反应属性myArray
已更改并安排了渲染。
This is a larger change, but more maintainable and simpler.这是一个更大的变化,但更易于维护和更简单。 Instead of passing both the array and item id to each sub-component, only pass the item that the sub-component cares about.与其将数组和item id都传递给每个子组件,不如只传递子组件关心的item。
This does less work on the sub-component because each sub-component doesn't need to loop through the whole array to find the element that it cares about.这对子组件所做的工作较少,因为每个子组件不需要遍历整个数组来查找它关心的元素。
Working fixed playground from repro . 从 repro 工作的固定操场。
This approach requires a change in changeMyArray
.这种方法需要更改changeMyArray
。 Instead of mutating the items, new items need to be returned.不是改变项目,而是需要返回新项目。
changeMyArray() {
this.myArray = this.myArray.map(
(item) => {
return {...item, colored: !item.colored};
}
);
}
Breaking down that example.分解那个例子。 this.myArray.map
already returns a new array so the array spread is not required. this.myArray.map
已经返回一个新数组,因此不需要数组扩展。 Within the map
each item that is modified must return a new object.在map
中,每个被修改的项目都必须返回一个新的 object。 This is similar to how redux works and the linked article may provide more helpful details.这类似于redux 的工作方式,链接的文章可能会提供更多有用的详细信息。
Now the parent render function can be updated to pass the item directly to the subcomponent with: <li>${item.text} (<sub-component.item=${item}></sub-component>)</li>
.现在可以更新父渲染 function 以将项目直接传递给子组件: <li>${item.text} (<sub-component.item=${item}></sub-component>)</li>
。
Now when the item
changes, the sub-component automatically re-renders.现在,当item
更改时,子组件会自动重新渲染。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.