问题
*这不完全是我的情况,但这很重要。
想象一个呈现元素列表的应用程序:
const ElementsList = ({elements, <onElementTextChange>}) => (
<div className='ElementsList'>
{elements.map(el => (
<Element
key={el.id}
element={el}
/>
))}
</div>
)
元素保持在渲染的父组件的状态ElementsList
。每个元素都是一个简单的对象:
this.state = {elements: [
{id: 1, text: 'apple'},
{id: 23, text: 'banana'},
]}
...
render() { ... <ElementsList elements={this.state.elements}/> ... }
每个元素与附近的输入字段一起呈现以更改其文本:
export const Element = ({element, <onTextChange>}) => (
<div className='Element'>
<div className='element-text'>{element.text}</div>
<input type='text' value={element.text} onChange={???}></input>
</div>
)
考虑到可能有很多元素(应用程序可以处理的越多越好)。
现在的问题是我们应该如何通过这些输入来更新文本。
解决方案
我看到 2 个选项(它们的一些组合是可能的):
1.正确的反应方式(是吗?) - 通知父组件有关更改
- 在元素:
onChange={evt => onTextChange(evt.target.value)}
- 在元素列表:
onTextChange={newText => onElementTextChange(el, newText)}
- 在父组件:
onElementTextChange={ (element, newText) => {make new elements array with the updated element somehow; setState(elements)} }
该解决方案似乎难以实施。与下面的替代方案相比,它也很慢。输入更改时发生的事件(如果我错了,请纠正我):
- 通过组件链通知父组件有关更改
- 父组件构造新元素数组并调用
setState
- 整个虚拟 DOM 得到更新(包括每个元素)
- 更新的虚拟 DOM 与之前的虚拟 DOM 版本进行比较
- 一个元素在真实 DOM 中更新
2.直接更新Element的propsforceUpdate()
- 将 Element 重写为类而不是功能组件
- 在元素处:onChange={evt => {element.text = evt.target.value; this.forceUpdate()}}
输入更改时发生的事件:
- props.element.text 被改变并被
forceUpdate
调用 - 虚拟 DOM 中只有一个元素被更新
- 将虚拟 DOM(一个元素)的更新子树与旧虚拟 DOM 进行比较
- 一个元素在真实 DOM 中更新
问题
目前我正在使用一种中间方法,但更多的是在“适当的反应方式”方面。而且速度还不够快。
我更喜欢第二种选择,它需要更少的代码,而且看起来它应该工作得更快(理论上)。
- 使用第二种方法会显着提高性能吗?(记住有成千上万的元素)
- 这种方法会导致哪些具体问题?是的,是的,我知道代码不那么透明,这不是它的本意。
- 您还有其他提高性能的方法吗?我很乐意尝试更少的类似反应的建议,可能会考虑部分或完全放弃反应。