freeCodeCamp/curriculum/challenges/portuguese/03-front-end-libraries/react/optimize-re-renders-with-sh...

5.3 KiB

id title challengeType forumTopicId dashedName
5a24c314108439a4d4036180 Otimizar Re-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 e 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 re-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 booleano 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 re-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 <code>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 re-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>
    );
  }
}