5.3 KiB
id, title, challengeType, forumTopicId, dashedName
id | title | challengeType | forumTopicId | dashedName |
---|---|---|---|---|
5a24c314108439a4d4036180 | Otimizar novas renderizações com shouldComponentUpdate | 6 | 301398 | optimize-re-renders-with-shouldcomponentupdate |
--description--
Até agora, se qualquer componente recebe um novo state
ou novas props
, ele se renderiza novamente com todos os seus filhos. Normalmente isto está ok. Mas React fornece um método de ciclo de vida que você pode chamar quando componentes filhos recebem um novo state
ou props
, e declarar especificamente se os componentes devem atualizar ou não. O método é shouldComponentUpdate()
, e leva nextProps
e nextState
como parâmetros.
Esse método é uma maneira útil de otimizar o desempenho. Por exemplo, o comportamento padrão é que seu componente renderiza novamente quando recebe novas props
, mesmo que as props
não tenham mudado. Você pode usar shouldComponentUpdate()
para evitar isso comparando as props
. O método deve retornar um valor boolean
que indica ao React se deve ou não atualizar o componente. Você pode comparar os "props" atuais (this.props
) para os próximos props (nextProps
) para determinar se você precisa atualizar ou não, e retorne true
ou false
de acordo.
--instructions--
O método shouldComponentUpdate()
é adicionado em um componente chamado OnlyEvens
. Atualmente, esse método retorna true
então OnlyEvens
renderiza novamente toda vez que recebe novas props
. Modifique o método para que OnlyEvens
seja atualizado somente se os value
de suas novas props forem par. Clique no botão Add
e veja a ordem dos eventos no console do seu navegador enquanto os ganchos de ciclo de vida são ativados.
--hints--
O componente Controller
deve renderizar o componente OnlyEvens
como um filho.
assert(
(() => {
const mockedComponent = Enzyme.mount(React.createElement(Controller));
return (
mockedComponent.find('Controller').length === 1 &&
mockedComponent.find('OnlyEvens').length === 1
);
})()
);
O método shouldComponentUpdate
deve ser definido no componente OnlyEvens
.
assert(
(() => {
const child = React.createElement(OnlyEvens)
.type.prototype.shouldComponentUpdate.toString()
.replace(/s/g, '');
return child !== 'undefined';
})()
);
O componente OnlyEvens
deve retornar uma tag h1
que renderiza o valor de this.props.value
.
(() => {
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 === '<h1>1000</h1>' && secondValue === '<h1>10</h1>');
})();
OnlyEvens
deve renderizar novamente somente quando nextProps.value
for par.
(() => {
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--
ReactDOM.render(<Controller />, document.getElementById('root'));
--seed-contents--
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 <h1>{this.props.value}</h1>;
}
}
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 (
<div>
<button onClick={this.addValue}>Add</button>
<OnlyEvens value={this.state.value} />
</div>
);
}
}
--solutions--
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 <h1>{this.props.value}</h1>;
}
}
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 (
<div>
<button onClick={this.addValue}>Add</button>
<OnlyEvens value={this.state.value} />
</div>
);
}
}