Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React.PureComponent doesn't work when the Component has children?

It seems a common technic to use PureComponent to improve rendering perf in React. However, it seems not the case when using PureComponent who has children as props.

class App extends React.PureComponent {
  render() {
    console.log('re-render') 
    return <div>{this.props.children}</div>
  }
}

const render = () => {
  ReactDOM.render(
    <App>
      <div />
    </App>,
    document.getElementById('app')
  )
  setTimeout(render, 1000)
}

render()

The result is that console keeps logging 're-render' every 1s. It seems the children(<div />) is the only prop of above App component and never changes, why App still gets re-rendered?

Note: in case of any confusion, the question is the same as, why SCU(shouldComponentUpdate) hook of PureComponent above return true since no props seems changed?

like image 986
lxyyz Avatar asked Jan 05 '18 05:01

lxyyz


People also ask

Can React components have children?

React Components and Children In React, a component can have one, many, or no children.

Does React always re-render children?

This doesn't only mean the component's render function will be called, but also that all its subsequent child components will re-render, regardless of whether their props have changed or not.

When might u Use React PureComponent?

If your React component's render() function renders the same result given the same props and state, you can use React. PureComponent for a performance boost in some cases.

How do you prevent a child component from rendering?

memo() If you're using a React class component you can use the shouldComponentUpdate method or a React. PureComponent class extension to prevent a component from re-rendering.


1 Answers

What happen here is you're actually calling ReactDOM.render(), Page (or App, I suppose you have a typo here) component is gonna trigger its render() function regardless of using Component or PureComponent.

The way PureComponent can help to reduce unnecessary rendering is when there is a prop change, PureComponent will do a shallow comparison on this.props and nextProps to determine if this PureComponent needs to call render().


I just made this example for you:

class App extends React.PureComponent {
  state = {value: 0}

  componentDidMount() {
    setInterval(() => {
      this.setState({value: Math.random()})
    }, 1000)
  }

  render() {
    return (
      <div>
        <PureChild value="fixed value"/>
        <ImpureChild value="fixed value"/>
      </div>
    )
  }
}

class PureChild extends React.PureComponent {
  render() {
    console.log('rendering PureChild')
    return <div>{this.props.value}</div>
  }
}

class ImpureChild extends React.Component {
  render() {
    console.log('rendering ImpureChild')
    return <div>{this.props.value}</div>
  }
}

Pay attention to this few things:

  1. Both children are receiving a fixed props ("fixed value" string)
  2. Every 1 second, the parent <App /> change value state, thus it re-renders, causing all its children to re-render as well.
  3. But since <PureChild /> is a PureComponent, it does a shallow comparison on its old props and incoming new props, and notices both props are "fixed value", and therefore it doesn't trigger render!

If you run this code and open up console, you'll see only 'rendering ImpureChild' every 1s, but 'rendering PureChild' will only appear once.

like image 74
Liren Yeo Avatar answered Sep 28 '22 09:09

Liren Yeo