为什么React调用未更改组件的render方法?

时间:2016-11-27 22:21:22

标签: reactjs

我很好奇React在这种情况下更新子组件的原因:

function Inner(props) {
  console.log("Render Inner");
  return <div>Inner</div>;
}

export class Outer extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      active: false
    };
    this.onClick = this.rawOnClick.bind(this);
  }

  render() {
    console.log("Render Outer");
    return <div onClick={this.onClick} style={{ backgroundColor: this.state.active ? 'red': 'blue'}}><Inner/></div>;
  }

  rawOnClick(event) {
    this.setState({ active: !this.state.active });
  }
}


ReactDOM.render(<Outer/>, document.getElementById('app'));

单击组件Outer时,将调用Inner和Outer的render方法。由于组件应该是“纯粹的”,因此不需要调用Inner的render方法,是吗?如果我稍微重写一下代码,我甚至可以这样做:

export function Inner(props) {
  console.log("Render Inner");
  return <div>Inner</div>;
}

export class Outer2 extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      active: false
    };
    this.onClick = this.rawOnClick.bind(this);
  }

  render() {
    console.log("Render Outer");
    return <div onClick={this.onClick} style={{ backgroundColor: this.state.active ? 'red': 'blue'}}>{this.props.children}</div>;
  }

  rawOnClick(event) {
    this.setState({ active: !this.state.active });
  }
}

ReactDOM.render(<Outer2><Inner /></Outer2>, document.getElementById('app'));

现在,单击组件时,只调用“Outer2”的render方法。这是故意的吗?这是一项任务优化,还是我错过了重要的事情。

感谢。

彼得

2 个答案:

答案 0 :(得分:1)

这是React的默认行为。您必须覆盖Inner组件中的shouldComponentUpdate()以返回true或false以确定是否需要再次调用其自己的render()。这种决定通常是根据当前和下一组道具和州之间的差异(如果有的话)做出的。

在您的示例中,您的Inner组件始终返回相同的内容并且不会受到props或state更改的影响,您只能返回false。

shouldComponentUpdate(nextProps, nextState) {
  return false;
};

(注意,您必须将Inner从无状态函数转换为ES6类才能使用此生命周期方法。)

阅读更多官方文档 - https://facebook.github.io/react/docs/react-component.html#shouldcomponentupdate

答案 1 :(得分:1)

在第一种情况下,外部组件的状态在触发click事件时发生变化。由于状态更改,将触发render方法。由于内部组件位于render方法内部,因此它也会被重新渲染,并且内部组件的render方法也会被调用。

因为在第二种情况下,内部组件不在外部组件的render方法内部,所以即使外部组件的状态发生变化,它也不会重新渲染。

只有当您没有将外部组件状态的内容作为道具传递给内部组件时,您的第二种情况才有效。一旦你这样做,状态键的改变作为一个道具传递到内部组件将再次触发内部组件的渲染方法

如果你想将一些东西从外部组件状态传递给内部组件作为prop,并避免对内部组件进行不必要的渲染调用,那么你将不得不从无状态内部组件转移到一个类基于内部组件和用户 shouldComponentUpdate 生命周期方法来限制内部组件的渲染方法被调用