--- id: 5a24c314108439a4d4036180 title: Optimize Re-Renders with shouldComponentUpdate challengeType: 6 forumTopicId: 301398 dashedName: optimize-re-renders-with-shouldcomponentupdate --- # --description-- So far, if any component receives new `state` or new `props`, it re-renders itself and all its children. This is usually okay. But React provides a lifecycle method you can call when child components receive new `state` or `props`, and declare specifically if the components should update or not. The method is `shouldComponentUpdate()`, and it takes `nextProps` and `nextState` as parameters. This method is a useful way to optimize performance. For example, the default behavior is that your component re-renders when it receives new `props`, even if the `props` haven't changed. You can use `shouldComponentUpdate()` to prevent this by comparing the `props`. The method must return a `boolean` value that tells React whether or not to update the component. You can compare the current props (`this.props`) to the next props (`nextProps`) to determine if you need to update or not, and return `true` or `false` accordingly. # --instructions-- The `shouldComponentUpdate()` method is added in a component called `OnlyEvens`. Currently, this method returns `true` so `OnlyEvens` re-renders every time it receives new `props`. Modify the method so `OnlyEvens` updates only if the `value` of its new props is even. Click the `Add` button and watch the order of events in your browser's console as the lifecycle hooks are triggered. # --hints-- The `Controller` component should render the `OnlyEvens` component as a child. ```js assert( (() => { const mockedComponent = Enzyme.mount(React.createElement(Controller)); return ( mockedComponent.find('Controller').length === 1 && mockedComponent.find('OnlyEvens').length === 1 ); })() ); ``` The `shouldComponentUpdate` method should be defined on the `OnlyEvens` component. ```js assert( (() => { const child = React.createElement(OnlyEvens) .type.prototype.shouldComponentUpdate.toString() .replace(/s/g, ''); return child !== 'undefined'; })() ); ``` The `OnlyEvens` component should return an `h1` tag which renders the value of `this.props.value`. ```js (() => { const mockedComponent = Enzyme.mount(React.createElement(Controller)); const first = () => { mockedComponent.setState({ value: 1000 }); return mockedComponent.find('h1').html(); }; const second = () => { mockedComponent.setState({ value: 10 }); return mockedComponent.find('h1').html(); }; const firstValue = first(); const secondValue = second(); assert(firstValue === '

1000

' && secondValue === '

10

'); })(); ``` `OnlyEvens` should re-render only when `nextProps.value` is even. ```js (() => { const mockedComponent = Enzyme.mount(React.createElement(Controller)); const first = () => { mockedComponent.setState({ value: 8 }); return mockedComponent.find('h1').text(); }; const second = () => { mockedComponent.setState({ value: 7 }); return mockedComponent.find('h1').text(); }; const third = () => { mockedComponent.setState({ value: 42 }); return mockedComponent.find('h1').text(); }; const firstValue = first(); const secondValue = second(); const thirdValue = third(); assert(firstValue === '8' && secondValue === '8' && thirdValue === '42'); })(); ``` # --seed-- ## --after-user-code-- ```jsx ReactDOM.render(, document.getElementById('root')); ``` ## --seed-contents-- ```jsx class OnlyEvens extends React.Component { constructor(props) { super(props); } shouldComponentUpdate(nextProps, nextState) { console.log('Should I update?'); // Change code below this line return true; // Change code above this line } componentDidUpdate() { console.log('Component re-rendered.'); } render() { return

{this.props.value}

; } } class Controller extends React.Component { constructor(props) { super(props); this.state = { value: 0 }; this.addValue = this.addValue.bind(this); } addValue() { this.setState(state => ({ value: state.value + 1 })); } render() { return (
); } } ``` # --solutions-- ```jsx class OnlyEvens extends React.Component { constructor(props) { super(props); } shouldComponentUpdate(nextProps, nextState) { console.log('Should I update?'); // Change code below this line return nextProps.value % 2 === 0; // Change code above this line } componentDidUpdate() { console.log('Component re-rendered.'); } render() { return

{this.props.value}

; } } class Controller extends React.Component { constructor(props) { super(props); this.state = { value: 0 }; this.addValue = this.addValue.bind(this); } addValue() { this.setState(state => ({ value: state.value + 1 })); } render() { return (
); } } ```