传递对象时防止在PureComponent上重新渲染

时间:2019-08-29 08:12:17

标签: javascript reactjs

使用PureComponents时,与功能组件相比,优点是父组件更新时并不总是呈现该组件。实际上,它仅在组件属性发生变化时才进行渲染,在此示例中,仅当您更改输入时才发生。

如何在不破坏使用这种组件的所有优点的情况下将对象传递给PureComponent?

这是否意味着一旦您拥有一个预计会成为对象类型的道具,最好使您的组件起作用?

我添加了一个示例来说明我的意思...(可能您需要在新窗口中打开它,因为有很多不同的孩子)

class TestPureComponent extends React.PureComponent {
  render() {
    return <div style={{border: '1px solid black'}}>{this.props.text} : {this.props.inputValue} {Math.random()} <button onClick={() => {this.props.dismissClicked()}}>Click me</button>  </div>
  }
}

function TestFunctionalComponent () {
  return <div style={{border: '1px solid black'}}>I always update as I am a functional component {Math.random()}</div>
}

const hell = () => {console.log('Logs hello')}

class RenderExample extends React.Component {
  constructor (props) {
    super(props)
    this.state = {clicked: false, inputValue: 'inputValue'}
    this.onClick = this.onClick.bind(this)
    this.doSomething = this.doSomething.bind(this)
  }

  onClick () {
    this.setState({clicked: !this.state.clicked})
  }
  
  doSomething () {
    console.log('helllllo')
  }
  
  heee = () => {
    console.log('heeeee')
  }

  render () {
    return <div>
      <button onClick={this.onClick}>
        Update state (forces re-render) {this.state.clicked && 'clicked'}
      </button>
      <input onChange={(e) => this.setState({inputValue: e.target.value})} type="text" value={this.state.inputValue}/>
      <br/>
      <br/>
      <TestFunctionalComponent />
      <br/>
      <TestPureComponent dismissClicked={() => hell} inputValue={this.state.inputValue} text="If you click the button this will re-render, if you change the input this will re-render"/>
      <br/>
      <TestPureComponent text="If you click the button this will NOT re-render, if you change the input this will re-render" dismissClicked={this.doSomething} inputValue={this.state.inputValue}/>
      <br/>
      <TestPureComponent text="If you click the button this will NOT re-render, if you change the input this will re-render" dismissClicked={this.heee} inputValue={this.state.inputValue}/>
      <br/>
      <TestPureComponent text="If you click the button this will NOT re-render, if you change the input this will re-render" dismissClicked={hell} inputValue={this.state.inputValue}/>
      <br/>
      <TestPureComponent text="If you click the button this will NOT re-render, if you change the input this will re-render" dismissClicked={hell} inputValue={this.state.inputValue}/>
      <br/><br/>
      <div> we will now add an inline object to each component and now they all update</div>
      
      <TestPureComponent dismissClicked={() => hell} inlineOBJ={{hello: 'world'}} inputValue={this.state.inputValue} text="If you click the button this will re-render, if you change the input this will re-render"/>
      <br/>
      <TestPureComponent text="If you click the button this will re-render, if you change the input this will re-render" inlineOBJ={{hello: 'world'}} dismissClicked={this.doSomething} inputValue={this.state.inputValue}/>
      <br/>
      <TestPureComponent text="If you click the button this will re-render, if you change the input this will re-render" inlineOBJ={{hello: 'world'}} dismissClicked={this.heee} inputValue={this.state.inputValue}/>
      <br/>
      <TestPureComponent text="If you click the button this will re-render, if you change the input this will re-render" inlineOBJ={{hello: 'world'}} dismissClicked={hell} inputValue={this.state.inputValue}/>
      <br/>
      <TestPureComponent text="If you click the button this will re-render, if you change the input this will re-render" inlineOBJ={{hello: 'world'}} dismissClicked={hell} inputValue={this.state.inputValue}/>
    </div>
  }
}

ReactDOM.render(<RenderExample />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="root"></div>

我想要的是看看是否有一种方法可以拥有PureComponent,当有对象作为道具传入时,它永远不会更新。

1 个答案:

答案 0 :(得分:3)

您必须将该对象存储在某个位置,以免在每次重新渲染时都生成该对象。这也适用于在渲染过程中生成的函数(dismissClicked = {()=> hell})。

如果使用render函数,则函数应位于外部,这样就不会为每个渲染都创建这样的函数:        dismissClicked = {this.hell}

对于对象,只需将其保存为状态即可。

您可以使用功能组件完全相同。使用备注包装组件以进行浅表比较。

为防止在每个渲染器上生成函数,请使用useCallback和useState保存要传递给子级的对象,以使引用保持不变。

您可以使用useEffect轻松更新这些对象。

希望这会有所帮助。编码愉快。