--- id: 5a24c314108439a4d4036180 title: Optimize Re-Renders with shouldComponentUpdate challengeType: 6 isRequired: false --- ## 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 other lifecycle hooks are triggered.
## Tests
```yml tests: - text: The Controller component should render the OnlyEvens component as a child. testString: assert((() => { const mockedComponent = Enzyme.mount(React.createElement(Controller)); return mockedComponent.find('Controller').length === 1 && mockedComponent.find('OnlyEvens').length === 1; })(), 'The Controller component should render the OnlyEvens component as a child.'); - text: The shouldComponentUpdate method should be defined on the OnlyEvens component. testString: assert((() => { const child = React.createElement(OnlyEvens).type.prototype.shouldComponentUpdate.toString().replace(/s/g,''); return child !== 'undefined'; })(), 'The shouldComponentUpdate method should be defined on the OnlyEvens component.'); - text: The OnlyEvens component should return an h1 tag which renders the value of this.props.value. testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(Controller)); const first = () => { mockedComponent.setState({ value: 1000 }); return waitForIt(() => mockedComponent.find(''h1'').html()); }; const second = () => { mockedComponent.setState({ value: 10 }); return waitForIt(() => mockedComponent.find(''h1'').html()); }; const firstValue = await first(); const secondValue = await second(); assert(firstValue === ''

1000

'' && secondValue === ''

10

'', ''The OnlyEvens component should return an h1 tag which renders the value of this.props.value.''); }; ' - text: OnlyEvens should re-render only when nextProps.value is even. testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(Controller)); const first = () => { mockedComponent.setState({ value: 8 }); return waitForIt(() => mockedComponent.find(''h1'').text()); }; const second = () => { mockedComponent.setState({ value: 7 }); return waitForIt(() => mockedComponent.find(''h1'').text()); }; const third = () => { mockedComponent.setState({ value: 42 }); return waitForIt(() => mockedComponent.find(''h1'').text()); }; const firstValue = await first(); const secondValue = await second(); const thirdValue = await third(); assert(firstValue === ''8'' && secondValue === ''8'' && thirdValue === ''42'', ''OnlyEvens should re-render only when nextProps.value is even.''); }; ' ```
## Challenge Seed
```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 } componentWillReceiveProps(nextProps) { console.log('Receiving new props...'); } 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({ value: this.state.value + 1 }); } render() { return (
); } }; ```
### After Test
```js ReactDOM.render(, document.getElementById('root')) ```
## Solution
```js 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 } componentWillReceiveProps(nextProps) { console.log('Receiving new props...'); } 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({ value: this.state.value + 1 }); } render() { return (
); } }; ```