【问题标题】:Change react props within component as optimization更改组件内的 react props 作为优化
【发布时间】:2023-03-16 23:00:02
【问题描述】:

问题

*这不完全是我的情况,但重要的是这里。
想象一个呈现元素列表的应用:

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 =&gt; onTextChange(evt.target.value)}
  • 在 ElementsList:onTextChange={newText =&gt; onElementTextChange(el, newText)}
  • 在父组件处:onElementTextChange={ (element, newText) =&gt; {make new elements array with the updated element somehow; setState(elements)} }

该解决方案似乎难以实施。与下面的替代方案相比,它也很慢。输入更改时发生的事件(如果我错了,请纠正我):

  1. 通过组件链通知父组件有关更改
  2. 父组件构造新元素数组并调用setState
  3. 整个虚拟 DOM 得到更新(包括每个元素)
  4. 更新的虚拟 DOM 与之前的虚拟 DOM 版本进行比较
  5. 一个元素在真实 DOM 中更新

2。直接更新 Element 的 props 和 forceUpdate()

  • 将 Element 重写为类而不是功能组件
  • 在元素处:onChange={evt => {element.text = evt.target.value; this.forceUpdate()}}

输入更改时发生的事件:

  1. props.element.text 被改变,forceUpdate 被调用
  2. 仅更新虚拟 DOM 中的一个元素
  3. 将虚拟 DOM(一个元素)的更新子树与旧虚拟 DOM 进行比较
  4. 一个元素在真实 DOM 中更新

问题

目前我正在使用一种中间方法,但更多的是在“适当的反应方式”方面。而且速度还不够快。
我更喜欢第二个选项,它需要的代码更少,而且看起来应该运行得更快(理论上)。

  1. 使用第二种方法会显着提高性能吗? (记住有成千上万的元素)
  2. 这种方法会导致哪些具体问题?是的,是的,我知道代码不那么透明,这不是它的本意。
  3. 您还有其他提高性能的方法吗?我很乐意尝试更少的类似 react 的建议,可能会考虑部分或完全放弃 react。

【问题讨论】:

  • 我会使用选项 2,但我不确定如何回答您的问题。为了衡量性能,React 刚刚引入了profiler,因此您可以同时尝试两者,看看性能影响是什么。
  • @Toby 谢谢。我会尝试测量性能

标签: javascript reactjs react-props react-lifecycle react-state-management


【解决方案1】:

你可以这样做

 this.state = {elements: [
  {id: 1, text: 'apple'},
   {id: 23, text: 'banana'},
   ]}

   // creating a update function which you will pass down to the child

    updateState = (id, val) => {
           const newElements = this.state.elements;
            newElements.map(item => {
               if(item.id === id) item.text = val;
             });
          this.setState({
           elements: newElements,
          })
       }
 render() { ... <ElementsList elements={this.state.elements} updateState ={this.updateState}/> ... }

现在在 ElementsList 中

       const ElementsList = ({elements, updateState,  <onElementTextChange>}) => (
       <div className='ElementsList'>
        {elements.map(el => (
       <Element
        key={el.id}
        element={el}
        updateState = {updateState}
         />
        ))}
        </div>
         )

现在在元素中

    export class Element extends React.Component{

     state = {
       value: '',  
       }
         onChangeValue = (e) => { 
              this.setState({ value: e.target.value});
            // calling the parent function directly
               this.props.updateState(this.props.element.id, e.target.value);
            }
       componentDidMount(){
         this.setState({
         value: this.props.element.text,
       })
         }
      render(){
        return(
              <div className='Element'>
       <div className='element-text'>{element.text}</div>
       <input type='text' value={this.state.value} onChange={this.onChangeValue}></input>
       </div>
        )
        }
       } 

【讨论】:

  • 这是一种不同的方法。但是关于我的第一个解决方案的所有担忧都适用于此。除了通知链更简单。
【解决方案2】:

不可变数据结构通过记忆化和结构共享等技术解决您的性能问题。

您应该考虑使用Immutable.js。然后您可以使用React.PureComponent 对大型数据结构进行有效的值相等检查。

一个缺点是 Immutable.js 数据结构不能与常规的可变 javascript 数据结构很好地混合,这可能会令人沮丧。 Elm 或 ClojureScript 等一些语言为这些类型的数据结构提供一流的支持,使其体验更加一致。

【讨论】:

  • 它似乎根本没有帮助。 React 仍然会将所有元素重新渲染到虚拟 DOM 并执行树比较
猜你喜欢
  • 2019-09-11
  • 2018-07-01
  • 2016-09-12
  • 2021-07-28
  • 2015-08-24
  • 2019-12-05
  • 2020-05-01
  • 1970-01-01
  • 2019-06-04
相关资源
最近更新 更多