【问题标题】:Prevent render on the Second Component when state changes for the first当第一个组件的状态发生变化时,防止在第二个组件上渲染
【发布时间】:2018-09-16 00:59:46
【问题描述】:

我编写了一个简单的 React POC,其中有一个主组件和两个子组件。应用程序的整个状态都保存在 Main 组件中。当状态发生变化时,当新状态作为 props 传递时,子组件会重新渲染。

import * as React from 'react'
import * as ReactDOM from 'react-dom'
class Comp1 extends React.Component<IProps1, any> {
  render() {
    console.log('going to render Component1')
    return (
      <React.Fragment>
        <input type='text' value={this.props.curtext} onChange={(e) => this.props.handleChange(e.target.value)} />
        <button onClick={(e) => this.props.onSave(this.props.curtext)}>save</button>
      </React.Fragment> 
    )
  }
}
class Comp2 extends React.Component<IProps2, any> {
  render() {
    console.log('going to render Component2')
    return (
      <React.Fragment>
        <ul>
          {this.props.items.map((item, index) => <li key={index}>{item}</li>)}
        </ul>
      </React.Fragment>
    )
  }
}
class Main extends React.Component<any, IState> {
  constructor(props: any) {
    super(props)
    this.state = {
      currtext: "",
      items: []
    }
    this.handleChange = this.handleChange.bind(this)
    this.onSave = this.onSave.bind(this)
  }
  handleChange(text: string) {
    this.setState({currtext: text})
  }
  onSave(text: string) {
    var copy = this.state.items;
    copy.push(text)
    this.setState({currtext: "", items: copy})
  }
  render() {
    return (
      <React.Fragment>
        <Comp1 handleChange={this.handleChange} curtext={this.state.currtext} onSave={this.onSave} />
        <Comp2 items= {this.state.items} />
      </React.Fragment>
    )
  }
}

ReactDOM.render(<Main />, document.getElementById("root"))

interface IState {
  currtext: string
  items: Array<string>
}
interface IProps1 {
  handleChange: (text: string) => void,
  curtext: string,
  onSave: (text: string) => void
}

interface IProps2 {
  items: Array<string>
}

该应用唯一的问题是,当状态的“currtext”属性发生变化时,Component2仍然会重新渲染。

我所期望的是 curtext 发生变化,然后 Component1 被渲染,当项目发生变化时,Component2 重新渲染。

但现在我看到 Component2 在输入文本框中的每次击键时都会重新渲染,这只会改变 Component2 不关心的状态部分。

编辑:: 根据下面的建议,我将组件 2 的代码更改为

class Comp2 extends React.Component<IProps2, any> {
  shouldComponentUpdate(nextProps: IProps2, nextState: any) {
    console.log(nextProps.items);
    console.log(this.props.items);
    if (nextProps.items.toString() === this.props.items.toString()) {
      return false 
    } else { 
      return true
    }
  }
  render() {
    console.log('going to render Component2')
    return (
      <React.Fragment>
        <ul>
          {this.props.items.map((item, index) => <li key={index}>{item}</li>)}
        </ul>
      </React.Fragment>
    )
  }
}

现在,如果我在文本框中输入内容并单击保存。我看到 nextProps.items 和 this.props.items 总是相同的,因此我的 component2 根本不渲染。

【问题讨论】:

    标签: reactjs typescript


    【解决方案1】:

    Comp2 重新渲染的原因是,当父状态发生变化时,父渲染方法内部的所有内容都会重新渲染。

     class Comp2 extends React.Component<IProps2, any> {
      shouldComponentUpdate(nextProps, nextState) {
      if(nextProps.currtext) return false;
      return true;
      }
      render() {
        console.log('going to render Component2')
        return (
          <React.Fragment>
            <ul>
              {this.props.items.map((item, index) => <li key={index}>{item}</li>)}
            </ul>
          </React.Fragment>
        )
      }
    }
    

    尝试添加 shouldComponentUpdate 生命周期挂钩。

    将 currtext 作为道具传递给 Comp2。如果 currtext 包含一个字母 Comp2 将不会更新。一旦您提交并且 currtext 变为 "" 为空,它将更新。

    &lt;Comp2 items= {this.state.items} currtext={this.state.currtext} /&gt;

    也不要直接改变状态。

      onSave(text: string) {
        var copy = this.state.items.slice();
        copy.push(text)
        this.setState({currtext: "", items: copy})
      }
    

    【讨论】:

    • 我在上面更新了我的问题。对我来说 nextProps.items 总是等于 this.props.items。
    • 好吧,当 onSave 被调用时 nextProps.items 将不等于 this.Props.items 因为 nextProps.items 将在其中包含一个新字符串。但是试试这个实现
    • 是的,问题是我没有做切片。切片修复它。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-12
    • 2019-10-27
    • 1970-01-01
    相关资源
    最近更新 更多