避免在React中的每个更改事件上重新渲染

时间:2019-04-26 12:41:38

标签: javascript reactjs performance

我正在研究别人编写的现有React代码,并且面临一些性能问题。考虑以下代码片段:

//ComponentA.js
class ComponentA extends React.Component {
    this.state = { someValue : 'dummy' }
    // Other code

    // We are using Babel, so class fields are OK
    updateVal = e => this.setState({ someValue : e.target.value})
    // fetchData makes an ajax call
    fetchData = () => { fetch(this.state.someValue) }
    render() {
       return (
         <ComponentB val={this.state.someValue} 
                     updateVal={this.updateVal}
                     fetchData={this.fetchData}/>
       )
}

//ComponentB.js
class ComponentB extends React.Component {
    render() {
      return (    
        // Other code

        //Input is a component from a library
        <Input onChange={(e) => { this.updateValue(e) } } 
               onBlur={this.props.fetchData} />
               value={this.props.val}
      )
    }
}

现在的问题是,每当用户键入Input时,几秒钟后就会显示该值。这是因为ComponentA实际上是一个很大的组件(我知道它很糟糕,但是由于它很大而且我们没有太多时间,所以我现在不想对其进行重构),并且每次用户输入时都会重新渲染它。为避免这种情况,我可以使Input成为不受控制的组件,并更新ComponentA的{​​{1}} someValue。另一种方法是在onBlur中有一个initialState,它等于ComponentB道具。并且valonChange仅用于this.setState。然后ComponentB,我可以更新onBlur的{​​{1}}。

但是,在这两种方法中,React的ComponentA原理都丢失了。那么在这种情况下最好的解决方案是什么?

在这里我还要问,在这里使用不受控制的组件有什么害处?

2 个答案:

答案 0 :(得分:0)

一个快速解决方案可能是对onChange处理程序进行反跳。

我通常使用Lodash的debounce,但您可以使用另一个版本,也可以编写自己的版本。

import { debounce } from 'lodash'

class ComponentB extends React.Component {

    // componentA will rerender only every 300ms instead of every time user types
    handleChange = debounce(e => this.props.updateVal(e), 300)

    render() {
      return <Input onChange={this.handleChange} value={this.props.val} />
    }

}

最好的解决方案是拆分/重构componentA

答案 1 :(得分:0)

重新渲染进行了优化(我认为问题不在于组件尺寸)。 我认为问题不是由您的结构(这是React本身建议的)引起的,而是由库中的Input组件引起的。

您还可以将状态保留在ComponentB中并公开函数以获取/设置值,但是,正如您所说的那样,您将丢失single source of trouth,但是将避免重新呈现每个输入更改。

希望这会有所帮助!