Guia de Upgrade do React 19
25 de abril de 2024 por Ricky Hanlon
As melhorias adicionadas ao React 19 exigem algumas mudanças radicais, mas trabalhamos para tornar o upgrade o mais tranquilo possível e não esperamos que as mudanças afetem a maioria dos apps.
Neste post, vamos guiá-lo pelas etapas para o upgrade para o React 19:
- Instalação
- Codemods
- Breaking changes
- Novas descontinuações
- Mudanças notáveis
- Mudanças no TypeScript
- Changelog
Se você quiser nos ajudar a testar o React 19, siga as etapas neste guia de upgrade e relate quaisquer problemas que encontrar. Para obter uma lista de novos recursos adicionados ao React 19, consulte o post de lançamento do React 19.
Instalação
Para instalar a versão mais recente do React e React DOM:
npm install --save-exact react@^19.0.0 react-dom@^19.0.0
Ou, se você estiver usando Yarn:
yarn add --exact react@^19.0.0 react-dom@^19.0.0
Se você estiver usando TypeScript, também precisará atualizar os types.
npm install --save-exact @types/react@^19.0.0 @types/react-dom@^19.0.0
Ou, se você estiver usando Yarn:
yarn add --exact @types/react@^19.0.0 @types/react-dom@^19.0.0
Também estamos incluindo um codemod para as substituições mais comuns. Consulte Mudanças no TypeScript abaixo.
Codemods
Para ajudar com o upgrade, trabalhamos com a equipe do codemod.com para publicar codemods que atualizarão automaticamente seu código para muitas das novas APIs e padrões no React 19.
Todos os codemods estão disponíveis no repositório react-codemod
e a equipe do Codemod se juntou para ajudar a manter os codemods. Para executar esses codemods, recomendamos usar o comando codemod
em vez de react-codemod
porque ele é executado mais rápido, lida com migrações de código mais complexas e oferece melhor suporte para TypeScript.
As mudanças que incluem um codemod incluem o comando abaixo.
Para obter uma lista de todos os codemods disponíveis, consulte o repositório react-codemod
.
Breaking changes
Erros em render não são lançados novamente
Em versões anteriores do React, os erros lançados durante o render eram capturados e lançados novamente. Em DEV, também registraríamos no console.error
, resultando em logs de erros duplicados.
No React 19, melhoramos a forma como os erros são tratados para reduzir a duplicação, não lançando novamente:
- Erros não detectados: Os erros que não são detectados por limites de erro são relatados para
window.reportError
. - **Erros detectados: Os erros que são detectados por limites de erro são relatados para
console.error
.
Esta mudança não deve afetar a maioria dos apps, mas se seu relatório de erros de produção depender de erros sendo lançados novamente, você pode precisar atualizar o tratamento de erros. Para dar suporte a isso, adicionamos novos métodos a createRoot
e hydrateRoot
para tratamento de erros personalizado:
const root = createRoot(container, {
onUncaughtError: (error, errorInfo) => {
// ... log error report
},
onCaughtError: (error, errorInfo) => {
// ... log error report
}
});
Para obter mais informações, consulte a documentação para createRoot
e hydrateRoot
.
APIs React descontinuadas removidas
Removido: propTypes
e defaultProps
para funções
PropTypes
foram descontinuados em Abril de 2017 (v15.5.0).
No React 19, estamos removendo as verificações propType
do pacote React, e seu uso será silenciosamente ignorado. Se você estiver usando propTypes
, recomendamos migrar para TypeScript ou outra solução de verificação de tipo.
Também estamos removendo defaultProps
de componentes de função em vez de parâmetros padrão ES6. Componentes de classe continuarão a dar suporte a defaultProps
, pois não há alternativa ES6.
// Antes
import PropTypes from 'prop-types';
function Heading({text}) {
return <h1>{text}</h1>;
}
Heading.propTypes = {
text: PropTypes.string,
};
Heading.defaultProps = {
text: 'Hello, world!',
};
// Depois
interface Props {
text?: string;
}
function Heading({text = 'Hello, world!'}: Props) {
return <h1>{text}</h1>;
}
Removido: Contexto Legado usando contextTypes
e getChildContext
O Contexto Legado foi descontinuado em Outubro de 2018 (v16.6.0).
O Contexto Legado só estava disponível em componentes de classe usando as APIs contextTypes
e getChildContext
, e foi substituído por contextType
devido a bugs sutis que eram fáceis de ignorar. No React 19, estamos removendo o Contexto Legado para tornar o React um pouco menor e mais rápido.
Se você ainda estiver usando o Contexto Legado em componentes de classe, precisará migrar para a nova API contextType
:
// Antes
import PropTypes from 'prop-types';
class Parent extends React.Component {
static childContextTypes = {
foo: PropTypes.string.isRequired,
};
getChildContext() {
return { foo: 'bar' };
}
render() {
return <Child />;
}
}
class Child extends React.Component {
static contextTypes = {
foo: PropTypes.string.isRequired,
};
render() {
return <div>{this.context.foo}</div>;
}
}
// Depois
const FooContext = React.createContext();
class Parent extends React.Component {
render() {
return (
<FooContext value='bar'>
<Child />
</FooContext>
);
}
}
class Child extends React.Component {
static contextType = FooContext;
render() {
return <div>{this.context}</div>;
}
}
Removido: refs de string
Refs de string foram descontinuados em Março de 2018 (v16.3.0).
Componentes de classe suportavam refs de string antes de serem substituídos por ref callbacks devido a múltiplas desvantagens. No React 19, estamos removendo refs de string para tornar o React mais simples e fácil de entender.
Se você ainda estiver usando refs de string em componentes de classe, precisará migrar para ref callbacks:
// Antes
class MyComponent extends React.Component {
componentDidMount() {
this.refs.input.focus();
}
render() {
return <input ref='input' />;
}
}
// Depois
class MyComponent extends React.Component {
componentDidMount() {
this.input.focus();
}
render() {
return <input ref={input => this.input = input} />;
}
}
Removido: factories de padrão de módulo
Factories de padrão de módulo foram descontinuadas em Agosto de 2019 (v16.9.0).
Este padrão raramente era usado e dar suporte a ele faz com que o React seja ligeiramente maior e mais lento do que o necessário. No React 19, estamos removendo o suporte para factories de padrão de módulo, e você precisará migrar para funções regulares:
// Antes
function FactoryComponent() {
return { render() { return <div />; } }
}
// Depois
function FactoryComponent() {
return <div />;
}
Removido: React.createFactory
createFactory
foi descontinuado em Fevereiro de 2020 (v16.13.0).
Usar createFactory
era comum antes do suporte amplo para JSX, mas é raramente usado hoje em dia e pode ser substituído por JSX. No React 19, estamos removendo createFactory
, e você precisará migrar para JSX:
// Antes
import { createFactory } from 'react';
const button = createFactory('button');
// Depois
const button = <button />;
Removido: react-test-renderer/shallow
No React 18, atualizamos react-test-renderer/shallow
para reexportar react-shallow-renderer. No React 19, estamos removendo react-test-render/shallow
para preferir a instalação direta do pacote:
npm install react-shallow-renderer --save-dev
- import ShallowRenderer from 'react-test-renderer/shallow';
+ import ShallowRenderer from 'react-shallow-renderer';
APIs React DOM descontinuadas removidas
Removido: react-dom/test-utils
Movemos act
de react-dom/test-utils
para o pacote react
:
ReactDOMTestUtils.act
foi descontinuado em favor de React.act
. Importe act
de react
em vez de react-dom/test-utils
. Consulte https://react.dev/warnings/react-dom-test-utils para obter mais informações.Para corrigir este aviso, você pode importar act
de react
:
- import {act} from 'react-dom/test-utils'
+ import {act} from 'react';
Todas as outras funções test-utils
foram removidas. Essas utilidades eram incomuns e tornavam muito fácil depender de detalhes de implementação de baixo nível de seus componentes e do React. No React 19, essas funções darão erro quando chamadas e suas exportações serão removidas em uma versão futura.
Consulte a página de aviso para obter alternativas.
Removido: ReactDOM.render
ReactDOM.render
foi descontinuado em Março de 2022 (v18.0.0). No React 19, estamos removendo ReactDOM.render
, e você precisará migrar para usar ReactDOM.createRoot
:
// Antes
import {render} from 'react-dom';
render(<App />, document.getElementById('root'));
// Depois
import {createRoot} from 'react-dom/client';
const root = createRoot(document.getElementById('root'));
root.render(<App />);
Removido: ReactDOM.hydrate
ReactDOM.hydrate
foi descontinuado em Março de 2022 (v18.0.0). No React 19, estamos removendo ReactDOM.hydrate
, e você precisará migrar para usar ReactDOM.hydrateRoot
,
// Antes
import {hydrate} from 'react-dom';
hydrate(<App />, document.getElementById('root'));
// Depois
import {hydrateRoot} from 'react-dom/client';
hydrateRoot(document.getElementById('root'), <App />);
Removido: unmountComponentAtNode
ReactDOM.unmountComponentAtNode
foi descontinuado em Março de 2022 (v18.0.0). No React 19, você precisará migrar para usar root.unmount()
.
// Antes
unmountComponentAtNode(document.getElementById('root'));
// Depois
root.unmount();
For more see root.unmount()
for createRoot
and hydrateRoot
.
Removido: ReactDOM.findDOMNode
ReactDOM.findDOMNode
foi descontinuado em Outubro de 2018 (v16.6.0).
Estamos removendo findDOMNode
porque era uma exceção legada que era lenta para executar, frágil para refatorar, só retornava o primeiro filho e quebrava os níveis de abstração (veja mais aqui). Você pode substituir ReactDOM.findDOMNode
com refs do DOM:
// Antes
import {findDOMNode} from 'react-dom';
function AutoselectingInput() {
useEffect(() => {
const input = findDOMNode(this);
input.select()
}, []);
return <input defaultValue="Hello" />;
}
// Depois
function AutoselectingInput() {
const ref = useRef(null);
useEffect(() => {
ref.current.select();
}, []);
return <input ref={ref} defaultValue="Hello" />
}
Novas descontinuações
Descontinuado: element.ref
React 19 suporta ref
como uma prop, então estamos descontinuando o element.ref
em favor de element.props.ref
.
Acessar element.ref
irá avisar:
Descontinuado: react-test-renderer
Estamos descontinuando react-test-renderer
pois ele implementa seu próprio ambiente de renderização que não corresponde ao ambiente que os usuários usam, promove detalhes de implementação de teste e depende da introspecção dos detalhes internos do React.
O renderizador de teste foi criado antes que houvesse estratégias de teste mais viáveis disponíveis, como React Testing Library, e agora recomendamos o uso de uma biblioteca de teste moderna em vez disso.
No React 19, react-test-renderer
registra um aviso de descontinuação e mudou para renderização concorrente. Recomendamos migrar seus testes para @testing-library/react ou @testing-library/react-native para uma experiência de teste moderna e bem suportada.
Mudanças notáveis
Mudanças no StrictMode
React 19 inclui várias correções e melhorias no Strict Mode.
Ao renderizar duas vezes no Strict Mode em desenvolvimento, useMemo
e useCallback
reutilizarão os resultados memorizados da primeira renderização durante a segunda renderização. Componentes que já são compatíveis com o Strict Mode não devem notar uma diferença no comportamento.
Como acontece com todos os comportamentos do Strict Mode, esses recursos são projetados para revelar proativamente erros em seus componentes durante o desenvolvimento para que você possa corrigi-los antes de serem enviados para produção. Por exemplo, durante o desenvolvimento, o Strict Mode irá invocar duas vezes as funções de callback de ref na montagem inicial, para simular o que acontece quando um componente montado é substituído por um fallback de Suspense.
Melhorias no Suspense
No React 19, quando um componente suspende, o React irá commitar imediatamente o fallback do limite de Suspense mais próximo sem esperar que toda a árvore de irmãos seja renderizada. Depois que o fallback fizer o commit, o React agenda outra renderização para os irmãos suspensos para “pré-aquecer” as requisições lazy no resto da árvore:


Anteriormente, quando um componente suspendia, os irmãos suspensos eram renderizados e então o fallback era commited.


No React 19, quando um componente suspende, o fallback é commited e então os irmãos suspensos são renderizados.
Essa mudança significa que os fallbacks do Suspense exibem mais rapidamente, enquanto ainda aquecem as requisições lazy na árvore suspensa.
Builds UMD removidos
UMD foi amplamente utilizado no passado como uma maneira conveniente de carregar o React sem uma etapa de build. Agora, existem alternativas modernas para carregar módulos como scripts em documentos HTML. Começando com o React 19, o React não produzirá mais builds UMD para reduzir a complexidade de seu processo de teste e lançamento.
Para carregar o React 19 com uma tag de script, recomendamos o uso de um CDN baseado em ESM, como esm.sh.
<script type="module">
import React from "https://esm.sh/react@19/?dev"
import ReactDOMClient from "https://esm.sh/react-dom@19/client?dev"
...
</script>
Bibliotecas que dependem de internos do React podem bloquear atualizações
Esta versão inclui alterações nos internos do React que podem impactar bibliotecas que ignoram nossos apelos para não usar internos como SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
. Essas mudanças são necessárias para obter melhorias no React 19 e não quebrarão bibliotecas que seguem nossas diretrizes.
Com base em nossa Política de Versionamento, essas atualizações não estão listadas como breaking changes e não estamos incluindo documentos sobre como atualizá-las. A recomendação é remover qualquer código que dependa de internos.
Para refletir o impacto do uso de internos, renomeamos o sufixo SECRET_INTERNALS
:
_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE
No futuro, bloquearemos com mais agressividade o acesso aos internos do React para desencorajar o uso e garantir que os usuários não sejam impedidos de fazer o upgrade.
Mudanças no TypeScript
Tipos TypeScript descontinuados removidos
Limpeza dos tipos TypeScript com base nas APIs removidas no React 19. Alguns dos removidos tiveram os tipos movidos para pacotes mais relevantes, e outros não são mais necessários para descrever o comportamento do React.
Confira types-react-codemod
para uma lista de substituições suportadas. Se você achar que um codemod está faltando, ele pode ser rastreado na lista de codemods ausentes do React 19.
Limpezas de ref
necessárias
Essa mudança está incluída no preset de codemod react-19
como no-implicit-ref-callback-return
.
Devido à introdução de funções de limpeza de ref, retornar qualquer outra coisa de um callback de ref agora será rejeitado pelo TypeScript. A correção geralmente é parar de usar retornos implícitos:
- <div ref={current => (instance = current)} />
+ <div ref={current => {instance = current}} />
O código original retornou a instância do HTMLDivElement
e o TypeScript não saberia se isso deveria ser uma função de limpeza ou não.
useRef
requer um argumento
Essa mudança está incluída no preset de codemod react-19
como refobject-defaults
.
Uma reclamação de longa data de como TypeScript e React funcionam tem sido useRef
. Alteramos os tipos para que useRef
agora exija um argumento. Isso simplifica significativamente sua assinatura de tipo. Ele agora se comportará mais como createContext
.
// @ts-expect-error: Esperava-se 1 argumento, mas nenhum foi visto
useRef();
// Passa
useRef(undefined);
// @ts-expect-error: Esperava-se 1 argumento, mas nenhum foi visto
createContext();
// Passa
createContext(undefined);
Isso agora também significa que todas as refs são mutáveis. Você não atingirá mais o problema em que não pode mutar uma ref porque a inicializou com null
:
const ref = useRef<number>(null);
// Não é possível atribuir a 'current' porque é uma propriedade somente leitura
ref.current = 1;
MutableRef
agora está descontinuado em favor de um único tipo RefObject
que useRef
sempre retornará:
interface RefObject<T> {
current: T
}
declare function useRef<T>: RefObject<T>
useRef
ainda tem uma sobrecarga de conveniência para useRef<T>(null)
que retorna automaticamente RefObject<T | null>
. Para facilitar a migração devido ao argumento necessário para useRef
, uma sobrecarga de conveniência para useRef(undefined)
foi adicionada que retorna automaticamente RefObject<T | undefined>
.
Confira [RFC] Make all refs mutable para discussões anteriores sobre essa mudança.
Mudanças no tipo TypeScript ReactElement
Essa mudança está incluída no codemod react-element-default-any-props
.
As props
dos elementos React agora são padronizadas para unknown
em vez de any
se o elemento for tipado como ReactElement
. Isso não o afeta se você passar um argumento de tipo para ReactElement
:
type Example2 = ReactElement<{ id: string }>["props"];
// ^? { id: string }
Mas se você confiava no padrão, agora precisa lidar com unknown
:
type Example = ReactElement["props"];
// ^? Antes, era 'any', agora 'unknown'
Você só deve precisar disso se tiver muito código legado dependendo de acessos não seguros às props do elemento. A introspecção de elemento só existe como uma exceção e você deve deixar explícito que o acesso às suas props é insustentável por meio de um any
explícito.
O namespace JSX no TypeScript
Essa alteração está incluída no preset react-19
codemod como scoped-jsx
Um pedido de longa data é remover o namespace global JSX
de nossos tipos em favor de React.JSX
. Isso ajuda a evitar a poluição de tipos globais, o que impede conflitos entre diferentes bibliotecas de UI que alavancam JSX.
Agora você precisará encapsular a ampliação do módulo do namespace JSX em `declare module ”…”:
// global.d.ts
+ declare module "react" {
namespace JSX {
interface IntrinsicElements {
"my-element": {
myElementProps: string;
};
}
}
+ }
O especificador de módulo exato depende do tempo de execução JSX que você especificou nas compilerOptions
do seu tsconfig.json
:
- Para
"jsx": "react-jsx"
seriareact/jsx-runtime
. - Para
"jsx": "react-jsxdev"
seriareact/jsx-dev-runtime
. - Para
"jsx": "react"
e"jsx": "preserve"
seriareact
.
Melhores tipagens useReducer
useReducer
agora tem melhor inferência de tipos, graças a @mfp22.
No entanto, isso exigiu uma alteração de quebra onde useReducer
não aceita o tipo de redutor completo como um parâmetro de tipo, mas em vez disso, precisa de nenhum (e depender da tipagem contextual) ou precisa tanto do estado quanto do tipo de ação.
A nova melhor prática é não passar argumentos de tipo para useReducer
.
- useReducer<React.Reducer<State, Action>>(reducer)
+ useReducer(reducer)
Isso pode não funcionar em casos extremos em que você pode digitar explicitamente o estado e a ação, passando o Action
em uma tupla:
- useReducer<React.Reducer<State, Action>>(reducer)
+ useReducer<State, [Action]>(reducer)
Se você definir o redutor embutido, incentivamos a anotar os parâmetros da função:
- useReducer<React.Reducer<State, Action>>((state, action) => state)
+ useReducer((state: State, action: Action) => state)
Isso também é o que você também teria que fazer se mover o redutor para fora da chamada useReducer
:
const reducer = (state: State, action: Action) => state;
Changelog
Outras mudanças que quebram
- react-dom: Error for javascript URLs in
src
andhref
#26507 - react-dom: Remove
errorInfo.digest
fromonRecoverableError
#28222 - react-dom: Remove
unstable_flushControlled
#26397 - react-dom: Remove
unstable_createEventHandle
#28271 - react-dom: Remove
unstable_renderSubtreeIntoContainer
#28271 - react-dom: Remove
unstable_runWithPriority
#28271 - react-is: Remove deprecated methods from
react-is
28224
Outras mudanças notáveis
- react: Batch sync, default and continuous lanes #25700
- react: Don’t prerender siblings of suspended component #26380
- react: Detect infinite update loops caused by render phase updates #26625
- react-dom: Transitions in popstate are now synchronous #26025
- react-dom: Remove layout effect warning during SSR #26395
- react-dom: Warn and don’t set empty string for src/href (except anchor tags) #28124
Para uma lista completa de mudanças, consulte o Changelog.
Agradecimentos a Andrew Clark, Eli White, Jack Pope, Jan Kassens, Josh Story, Matt Carroll, Noah Lemen, Sophie Alpert, e Sebastian Silbermann por revisar e editar este post.