React v16.9.0 e a atualização do Roadmap

08 de agosto de 2019 por Dan Abramov and Brian Vaughn

Hoje estamos lançando o React 16.9. Ele contém vários novos recursos, correções de bugs e novos avisos de depreciação para ajudar a se preparar para uma futura versão principal.

Novas Depreciações

Renomeando Métodos de Ciclo de Vida Inseguros

Há mais de um ano, anunciamos que os métodos de ciclo de vida inseguros estão sendo renomeados:

  • componentWillMountUNSAFE_componentWillMount
  • componentWillReceivePropsUNSAFE_componentWillReceiveProps
  • componentWillUpdateUNSAFE_componentWillUpdate

O React 16.9 não contém alterações significativas e os nomes antigos continuam funcionando nesta versão. Mas agora você verá um aviso ao usar qualquer um dos nomes antigos:

Warning: componentWillMount foi renomeado e não é recomendado para uso.

Como o aviso sugere, geralmente há abordagens melhores para cada um dos métodos inseguros. No entanto, talvez você não tenha tempo para migrar ou testar esses componentes. Nesse caso, recomendamos a execução de um script “codemod” que os renomeia automaticamente:

cd seu_projeto
npx react-codemod rename-unsafe-lifecycles

(Note que ele diz npx, não npm. npx é um utilitário que vem com Node 6+ por padrão.)

A execução deste codemod substituirá os nomes antigos como componentWillMount pelos novos nomes como UNSAFE_componentWillMount:

Codemod em ação

Os novos nomes como UNSAFE_componentWillMount irão continuar a funcionar em ambos React 16.9 e em React 17.x. No entanto, o novo prefixo UNSAFE_ ajudará os componentes com padrões problemáticos a se destacarem durante os code review e depuração de código. (Se desejar, você pode desestimular ainda mais o uso dele dentro do seu aplicativo com o Strict Mode.)

Nota

Saiba mais sobre nossa política de versão e compromisso com a estabilidade.

Depreciando URLs javascript:

As URLs que começam com javascript: são uma superfície de ataque perigosa porque é fácil incluir acidentalmente uma saída não-tratada em uma tag <a href> e criar uma brecha de segurança:

const userProfile = {
  website: "javascript: alert('you got hacked')",
};
// This will now warn:
<a href={userProfile.website}>Profile</a>

Em React 16.9, esse padrão continua a funcionar, mas registrará um aviso. Se você usar javascript: na lógica das URLs, tente usar manipuladores de eventos React. (Como último recurso, você pode contornar a proteção dangerouslySetInnerHTML, mas é altamente desencorajado e muitas vezes leva a falhas de segurança.)

Em uma versão principal futura, React lançará um erro se encontrar um javascript: URL.

Depreciando Componentes “Factory”

Antes de compilar as classes JavaScript com o Babel se tornar popular, o React tinha suporte para um componente “factory” que retorna um objeto com um método render:

function FactoryComponent() {
  return { render() { return <div />; } }
}

Esse padrão é confuso porque parece muito com um componente de função - mas não é um. (Um componente de função apenas retornaria o <div /> do exemplo acima.)

Esse padrão quase nunca foi usado e o suportá-lo faz com que o React seja um pouco maior e mais lento do que o necessário. Então estamos depreciando este padrão na 16.9 e registrando um aviso se ele for encontrado. Se você confiar nele, a adição FactoryComponent.prototype = React.Component.prototype pode servir como uma solução alternativa. Alternativamente, você pode convertê-lo em uma classe ou em um componente de função.

Não esperamos que a maioria das bases de código seja afetadas por isso.

Novas Funcionalidades

Utilitário act() assíncrono para teste

O React 16.8 introduziu um novo utilitário de teste chamado act() para ajudá-lo a escrever testes que correspondam melhor ao comportamento do navegador. Por exemplo, várias atualizações de estado em um único act() são enfileiradas. Isso corresponde ao modo como o React já funciona ao manipular eventos reais do navegador e ajuda a preparar seus componentes para o futuro, no qual o React irá enfileirar atualizações com mais frequência.

No entanto, em 16.8 act() apenas suporta funções síncronas. Às vezes, você pode ter visto um aviso como este em um teste, mas não conseguiu corrigi-lo facilmente:

An update to SomeComponent inside a test was not wrapped in act(...).

No React 16.9, act() também aceita funções assíncronas, e você pode chamar o await:

await act(async () => {
  // ...
});

Isso resolve os casos restantes em que antes você não podia usar o act(), como quando a atualização do estado estava dentro de uma função assíncrona. Como resultado, você poderá corrigir todos os avisos do act() restantes em seus testes agora.

Ouvimos que não haviam informações suficientes sobre como escrever testes com act(). O novo guia Receitas de Testes descreve cenários comuns e como act() pode ajudar você a escrever bons testes. Esses exemplos usam APIs vanilla do DOM, mas você pode também usar o React Testing Library para reduzir o boilerplate de código. Muitos de seus métodos já usam act() internamente.

Por favor, informe-nos com uma issue se você se deparar com outros cenários em que act() não funciona bem para você e tentaremos ajudá-lo.

Medições de Desempenho com <React.Profiler>

Em React 16.5, introduzimos um novo React Profiler para o DevTools que ajuda a encontrar gargalos de desempenho em seu aplicativo. Em React 16.9, também estamos adicionando uma maneira programática de reunir as medições chamadas <React.Profiler>. Esperamos que a maioria dos aplicativos menores não os use, mas pode ser útil rastrear as regressões de desempenho ao longo do tempo em aplicativos maiores.

O <Profiler> mede com qual frequência uma aplicação React renderiza e qual o “custo” da renderização. Sua finalidade é ajudar identificar partes de um aplicativo que estão lentas e podem se beneficiar da otimização, como a memorização.

Um <Profiler> pode ser adicionado em qualquer lugar em uma árvore React para medir o custo de renderização dessa parte da árvore. Ele requer duas props: um id (string) e um onRender callback (função) que o React chama toda vez que um componente dentro da árvore “envia” uma atualização.

render(
  <Profiler id="application" onRender={onRenderCallback}>
    <App>
      <Navigation {...props} />
      <Main {...props} />
    </App>
  </Profiler>
);

Para saber mais sobre o Profiler e os parametros passado para o onRender callback, confira a documentação do Profiler.

Nota:

Profiling adiciona uma sobrecarga extra, portanto, ela é desativada na compilação de produção.

Para optar pelo profiling em produção, o React fornece uma compilação de produção especial com a criação de profiling ativo. Leia mais sobre como usar essa versão em fb.me/react-profiling.

Bugfixes Notáveis

Esta versão contém algumas outras melhorias notáveis:

  • Um problema ao chamar findDOMNode() dentro de um <Suspense> foi corrigido.

  • Um vazamento de memória causado pela retenção de subárvores excluídas também foi corrigido.

  • Um loop infinito causado por setState em useEffect agora registra um erro. (Isto é semelhante ao erro que você vê quando você chama setState em componentDidUpdate de uma classe.)

Agradecemos a todos os colaboradores que ajudaram a identificar e corrigir esses e outros problemas. Você pode encontrar o changelog completo abaixo.

Uma atualização para o Roadmap

Em Novembro de 2018, publicamos este roteiro para as versões 16.x:

  • Uma versão menor de 16.x com React Hooks (estimativa passada: Q1 2019)
  • Uma versão menor de 16.x com o Concurrent Mode (estimativa passada: Q2 2019)
  • Uma versão menor de 16.x com Suspense para Data Fetching (estimativa anterior: meados de 2019)

Essas estimativas eram otimistas demais e precisamos ajustá-las.

tldr: Nós lançamos os Hooks a tempo, mas estamos reagrupando o Concurrent Mode e Suspense para Data Fetching em uma única versão que pretendemos lançar ainda este ano.

Em fevereiro, nós lançamos a versão estável 16.8 incluindo o React Hooks, com suporte ao React Native um mês mais tarde. No entanto, subestimamos o trabalho de acompanhamento desta versão, incluindo as regras de lint, ferramentas de desenvolvimento, exemplos e mais documentação. Isso mudou a linha do tempo em alguns meses.

Agora que React Hooks foram lançados, o trabalho no Concurrent Mode e Suspense para Data Fetching está em pleno andamento. O novo site do Facebook que está atualmente em desenvolvimento ativo é construído sobre esses recursos. Testá-los com código real ajudou a descobrir e resolver muitos problemas antes que eles pudessem afetar os usuários de código aberto. Algumas dessas correções envolveram uma reformulação interna desses recursos, o que também fez com que a linha do tempo fosse alterada.

Com esse novo entendimento, aqui está o que planejamos fazer a seguir.

Um Lançamento em Vez de Dois

Concurrent Mode e Suspense fortalecem o novo site do Facebook que está em desenvolvimento ativo, por isso estamos confiantes de que estão perto de um estado estável tecnicamente. Agora também entendemos melhor as etapas concretas antes que elas estejam prontas para adoção de código aberto.

Originalmente, pensamos em dividir o Concurrent Mode e Suspense para Data Fetching em dois lançamentos. Descobrimos que esse sequenciamento é confuso para explicar porque esses recursos são mais relacionados do que pensávamos inicialmente. Portanto, planejamos lançar suporte para o Concurrent Mode e Suspense para Data Fetching em uma única versão.

Nós não queremos comprometer a data de lançamento novamente. Dado que confiamos em ambos no código de produção, esperamos fornecer uma versão 16.x com suporte opcional para eles este ano.

Uma Atualização na Busca de Dados

Embora o React não tenha opinião sobre como você busca dados, a primeira versão do Suspense para Data Fetching provavelmente focará a integração com bibliotecas de busca de dados opinativas. Por exemplo, no Facebook, estamos usando as APIs do Relay que se integram com o Suspense. Vamos documentar como outras bibliotecas opinativas como a Apollo podem suportar uma integração semelhante.

Na primeira versão, não pretendemos focar na solução ad-hoc “fire an HTTP request” que usamos nas demos anteriores (também conhecidas como “React Cache”). No entanto, esperamos que tanto nós como a comunidade React exploremos esse espaço nos meses após o lançamento inicial.

Uma Atualização na Renderização do Servidor

Iniciamos o trabalho no novo renderizador de servidor com capacidade para suspense, mas não esperamos que ele esteja pronto para a versão inicial do Concurrent Mode. Essa versão, no entanto, fornecerá uma solução temporária que permitirá que o renderizador do servidor existente emita HTML para fallbacks de Suspense imediatamente e, em seguida, renderize seu conteúdo real no cliente. Esta é a solução que estamos atualmente usando no Facebook até que o renderizador de streaming esteja pronto.

Por que Demora Tanto Tempo?

Lançamos as peças individuais que levaram ao Concurrent Mode quando elas se tornaram estáveis, incluindo a nova API de contexto, carregamento sob demanda com Suspense e Hooks. Também estamos ansiosos para liberar as outras partes que faltam, mas testá-las em escala é uma parte importante do processo. A resposta honesta é que isso só levou mais trabalho do que esperávamos quando começamos. Como sempre, agradecemos suas dúvidas e comentários no Twitter e em nossas issues.

Instalação

React

React v16.9.0 está disponível no registro npm.

Para instalar o React 16 com Yarn, execute:

yarn add react@^16.9.0 react-dom@^16.9.0

Para instalar o React 16 com npm, execute:

npm install --save react@^16.9.0 react-dom@^16.9.0

Nós também fornecemos compilações UMD de React via CDN:

<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

Consulte a documentação para instruções detalhadas de instalação.

Changelog

React

  • Adiciona API do <React.Profiler> para reunir medições de desempenho programaticamente. (@bvaughn em #15172)
  • Remove unstable_ConcurrentMode em favor de unstable_createRoot. (@acdlite em #15532)

React DOM

  • Deprecia nomes antigos dos métodos do ciclo de vida para os UNSAFE_*. (@bvaughn em #15186 e @threepointone em #16103)
  • Deprecia URLs javascript: como uma superfície de ataque comum. (@sebmarkbage em #15047)
  • Deprecia componentes incomuns do “module pattern” (factory). (@sebmarkbage em #15145)
  • Adiciona suporte para o atributo disablePictureInPicture em <video>. (@eek em #15334)
  • Adiciona suporte para o evento onLoad no <embed>. (@cherniavskii em #15614)
  • Adiciona suporte para editar estados criados por useState no DevTools. (@bvaughn em #14906)
  • Adiciona suporte para alterar o Suspense no DevTools. (@gaearon em #15232)
  • Avisa quando setState é chamado no useEffect, criando um loop. (@gaearon em #15180)
  • Corrige um vazamento de memória. (@paulshen em #16115)
  • Corrige uma falha dentro do findDOMNode dos componentes envolvidos por <Suspense>. (@acdlite em #15312)
  • Corrige efeitos pendentes de ser liberados muito tarde. (@acdlite em #15650)
  • Corrige ordem de argumento incorreta em uma messagem de aviso. (@brickspert em #15345)
  • Corrige a ocultação dos nós de fallback do Suspense quando houver um !important no estilo. (@acdlite em #15861 e #15882)
  • Melhora ligeiramente o desempenho de hidratação. (@bmeurer em #15998)

React DOM Server

  • Corrige a saída incorreta para nomes de propriedades CSS customizadas do camelCase. (@bedakb em #16167)

React Test Utilities e Test Renderer