ptriller
ptriller

Reputation: 325

Why does React call the render method of an unchanged component?

I am curious about why React updates the Child Component in this case:

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'));

When the component Outer is clicked, the render method of Inner and Outer are called. Since Components are supposed to be "pure" there is no need to call the render method of Inner, is there ? I can even make it that way, if I rewrite my code a little bit:

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'));

Now only the render method of "Outer2" is called when I click the component. Is this intentional ? Is this a mission optimization, or do I miss something important.

Thanks.

Peter

Upvotes: 0

Views: 558

Answers (2)

Swapnil
Swapnil

Reputation: 2603

In the first case, the outer component's state changes on triggering the click event. Due to the state change the render method is triggered. Since the inner component is inside the render method, it also gets re rendered and the inner component's render method gets called.

Since in the second case, the inner component is not inside the render method of the outer component, it will not re render even if the outer component's state changes.

Your second case will work only if you do not pass something from the outer component's state to the inner component as a prop. As soon as you do that, a change in state's key which is passed as a prop to the inner component will again trigger the render method of inner component

In case you want to pass something from the outer component's state to the inner component as a prop and avoid unnecessary render calls of inner component, you are going to have to move from a stateless inner component to a class based inner component and user the shouldComponentUpdate life cycle method to restrict the inner component's render method from being called

Upvotes: 1

Jeff McCloud
Jeff McCloud

Reputation: 5927

That is the default behavior of React. You must override shouldComponentUpdate() in your Inner component to return true or false to determine if its own render() needs to be called again. That determination is usually made based upon the differences, if any, found between the current and next set of props and state.

In your example, where your Inner component always returns the same thing and is never affected by changes to props or state, you can just return false.

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

(NOTE, you'll have to convert Inner from your stateless function to an ES6 class in order to use this lifecycle method.)

Read more at official docs - https://facebook.github.io/react/docs/react-component.html#shouldcomponentupdate

Upvotes: 1

Related Questions