React v16.3.0: Novos métodos de lifecycle e context API

No post anterior vimos sobre as futuras mudanças em alguns métodos de lifecycle. Na versão 16.3.0 estão sendo adicionados alguns métodos de lifecycle para ajudar com a migração. Também estão sendo introduzidas novas APIs para alguns recursos muito solicitados: uma API oficial para context, uma API para encaminhar refs, e uma API ref mais amigável.

Nota:

Este post é uma tradução do blog oficial do React, você pode ver o artigo original aqui

Nova Context API

Por muitos anos, React ofereceu uma API experimental para context. Embora fosse uma ferramenta poderosa, seu uso era desencorajado por causa de problemas inerentes na API, e porque o objetivo sempre foi que ela fosse substituída por uma API melhor.

A versão 16.3 introduz uma nova API de context que é mais eficiente e suporta tanto verificação de tipos estática, como atualizações profundas.

Nota:

A antiga API de context vai continuar funcionando durante as versões 16.x, assim você terá tempo para migrar.

A seguir um exemplo ilustrando como você pode injetar um “theme” usando a nova API de context:

const ThemeContext = React.createContext('light');

class ThemeProvider extends React.Component {
  state = {theme: 'light'};

  render() {
    return (
      <ThemeContext.Provider value={this.state.theme}>
        {this.props.children}
      </ThemeContext.Provider>
    );
  }
}

class ThemedButton extends React.Component {
  render() {
    return (
      <ThemeContext.Consumer>
        {theme => <Button theme={theme} />}
      </ThemeContext.Consumer>
    );
  }
}

Aprenda mais sobre a nova API de context aqui.

createRef API

Anteriormente, React fornecia duas maneiras de administrar refs: a API legada string ref e a API de callback. Embora a API string ref fosse a mais conveniente das duas, ela tinha várias desvantagens, por isso era recomendado usar a opção com callback.

A versão 16.3 adiciona uma nova opção para administrar refs, que oferece a conveniência de uma string ref, mas sem nenhuma das desvantagens:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);

    this.inputRef = React.createRef();
  }

  render() {
    return <input type="text" ref={this.inputRef} />;
  }

  componentDidMount() {
    this.inputRef.current.focus();
  }
}

Nota:

As refs de callback continuam a serem suportados, em adição a nova API createRef.

Você não precisa substituir refs de callback em seus componentes. Elas são um pouco mais flexíveis, por isso vão permanecer como um recurso avançado.

Aprenda mais sobre a nova API de createRef aqui.

forwardRef API

Geralmente, componentes React são declarativos, mas as vezes acesso imperativo as instâncias do componente e seus nodes DOM são necessárias. Isso é comum para casos de uso como administrar foco, seleção ou animações. React fornece refs como uma forma de resolver este problema. No entanto, encapsulamento de componentes gera alguns desafios com refs.

Por exemplo, se você substitui um <button> por um componente customizado <FancyButton>, o atributo ref nele irá começar a apontar para o componente que o envolve em vez do node DOM (e seria null para componentes funcionais). Embora isso seja desejável para componentes do “nível de aplicação” como FeedStory ou Comment que precisam ser encapsulados, pode ser irritante para componentes como FancyButton ou MyTextInput que são tipicamente usados como seus equivalentes DOM, e que precisam expor seus nodes DOM.

Encaminhamento de ref é uma nova funcionalidade opcional que permite alguns componentes pegar um ref que recebem, e passá-los ainda mais para baixo (em outras palavras, “adiante”) para um filho. No exemplo abaixo, FancyButton passa sua ref adiante para um button do DOM que este renderiza:

const FancyButton = React.forwardRef((props, ref) => (
  <button ref={ref} className="FancyButton">
    {props.children}
  </button>
));

// You can now get a ref directly to the DOM button:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;

Dessa forma, componentes usando FancyButton podem pegar o ref do node button do DOM e acessar, se for necessário, como que diretamente o button do DOM.

Passar adiante ref não é limitado a componentes que renderizam nodes DOM. Se você escrever componentes higher order, é recomendado passar adiante a ref para as instâncias do componente de classe empacotados.

Aprenda mais sobre a API forwardRef aqui.

Mudanças nos Lifecycle de Componentes

A API de class do React está disponível por bastante tempo já e com poucas alterações. Entretanto, conforme vai sendo adicionado suporte para recursos mais avançados (como error boundaries e o futuro modo async rendering este modelo foi estendido de maneiras que não eram originalmente pretendidas.

Por exemplo, com a API atual, é muito fácil bloquear o render inicial com lógica não essencial. Isso em parte acontece por existirem diversas maneiras de resolver uma tarefa, e pode não ser claro qual é a melhor. O comportamento de interromper, ao lidar com erros, com frequência não é levado em conta e pode resultar em memory leaks (algo que vai também impactar o futuro modo async rendering). A API de class atual também complica outros esforços, como criar um protótipo de um compilador React.

Muitos desses problemas são gerados por uma parte dos métodos de lifecycle (componentWillMount, componentWillReceiveProps, e componentWillUpdate). Estes também acabam sendo os lifecycles que mais causam confusão entre comunidade React. Por estas razões, estes métodos serão depreciados em favor de alternativas melhores.

Esta mudança vai causar impacto em muitos componentes existentes. Por causa disso, a migração será o mais gradual possível, e vão ser providas alternativas. (No Facebook, são mantidos mais de 50.000 componentes React. Eles também dependem de um release gradual)

Nota:

Avisos de depreciação serão habilitados em uma futura versão 16.x, mas os lifecycles legados vão continuar funcionando até a versão 17.

Mesmo na versão 17, ainda será possível usar eles, mas terão um prefix “UNSAFE_” para indicar que eles podem causar problemas. Também foi preparado um script que automatiza renomear eles em código existente.

Além de depreciar lifecycles que não são seguros, estão sendo adicionados dois novos lifecycles:

  • getDerivedStateFromProps está sendo adicionado como uma alternativa mais segura ao método legado componentWillReceiveProps.
  • getSnapshotBeforeUpdate está sendo adicionado para suportar ler propriedades de forma segura do DOM antes que sejam feitos updates.

Aprenda mais sobre estas mudanças de lifecycle aqui.

StrictMode Component

StrictMode é uma ferramenta para destacar possíveis problemas em uma aplicação. Assim como Fragment, StrictMode não renderiza nenhuma UI visível. Ele adiciona verificações adicionais e avisos para os seus descendentes.

Nota:

As verificações StrictMode rodam apenas em modo de desenvolvimento; não impactam o build de produção.

Embora não seja possível que o strict mode pegue todos os problemas (por exemplo, algumas mutações de tipos), ele pode ajudar em muitos. Se você ver avisos em strict mode, estes provavelmente vão causar bugs para o async rendering.

Na versão 16.3, StrictMode ajuda com:

  • Identificar componentes com métodos lifecycle que não são seguros
  • Avisar sobre usos da API string ref legada
  • Detectar efeitos colaterais inesperados

Funcionalidades adicionais serão adicionadas em futuras versões do React.

Aprenda mais sobre o componente StrictMode aqui.