Texto de: Marlliton Souza
Introdução
Recentemente, foi anunciado o React 19 RC, uma versão Release Candidate que traz várias melhorias e novidades para uma das tecnologias de desenvolvimento frontend mais populares do mercado, e neste artigo falaremos de algumas dessas novidades.
Ações (actions)
As actions nos permitem ouvir eventos disparados pelo usuário, seja um click, ou um envio de formulário e simplificam o gerenciamento de estados e mutação de dados que acontece em função desse evento.
Dessa forma podemos automatizar processos como lidar com estados pendentes e estados de erros, de forma mais eficiente. O que deixa nosso código mais limpo. Por exemplo, imagine que você está fazendo o envio de formulário de forma tradicional no React, provavelmente, você terá um código parecido com esse:
function Form() {
const [nome, setNome] = useState("");
const [erro, setErro] = useState(null);
const [carregando, setCarregando] = useState(false);
const submeter = async () => {
setCarregando(true);
const erro = await enviarNome(nome);
setCarregando(false);
if (erro) {
setErro(erro);
return;
}
redirect("/path");
};
return (
<div>
<input value={nome} onChange={valor => setNome(valor.target.value)} />
<button onClick={submeter} disabled={carregando}>
Enviar
</button>
{erro && <p>{erro}</p>}
</div>
);
}
Com o uso das actions, podemos automatizar, por exemplo, o estado de carregamento da aplicação usando useTransition:
function Form() {
const [nome, setNome] = useState("");
const [erro, setErro] = useState(null);
const [isPending, startTransition] = useTransition();
const submeter = () => {
startTransition(async () => {
const erro = await enviarNome(nome);
if (erro) {
setErro(erro);
return;
}
redirect("/path");
})
};
return (
<div>
<input value={nome} onChange={(event) => setNome(event.target.value)} />
<button onClick={submeter} disabled={isPending}>
Enviar
</button>
{erro && <p>{erro}</p>}
</div>
);
}
Com o uso do useTransition
não precisamos mais manipular estados de carregamento manualmente com o uso de estados, basta usarmos já que o isPending
será true
quando a transação começa e false
automaticamente quando ela termina com erro ou sucesso. Isso permite que a interface se mantenha interativa mesmo enquanto os dados estiverem sendo alterados.
Novo hook useActionState
O React 19 também introduziu o suporte para o useActionState
que é um hook que pode ser usado para gerenciar formulários automaticamente.
O useActionState
aceita uma função, que é chamada de action (ação), e retorna uma ação encapsulada que pode ser passada para o seu formulário. Essa ação irá gerenciar os estados possíveis do form de uma forma simples, o que permite que possamos gerenciar estados de erro e carregamento com facilidade.
import { redirect } from "next/navigation";
import { useActionState } from "react";
export default function Form() {
const [error, submitAction, isPending] = useActionState(
async (estadoAnterior, formData) => {
const error = await enviarNome(formData.get("nome"));
if (error) {
return error;
}
redirect("/path");
return null;
},
null,
);
return (
<form action={submitAction}>
<input type="text" name="nome" />
<button type="submit" disabled={isPending}>Enviar</button>
{error && <p>{error}</p>}
</form>
);
}
Nova API: use
De forma tradicional, sempre usamos estados (useState
) e efeitos colaterais (useEffect
) para lidar com requisições assíncronas. Usando a nova API use
podemos descartar o uso de useState
e useEffect
para lidar com esse tipo de requisições.
Basta passar a promessa para o método use
e ele mesmo se encarregará de fazer a suspensão dos componentes e quando o resultado da promessa chegar ele já se encarrega de “liberar” o uso dos dados que poderão ser renderizados em seguida.
import { Suspense, use } from "react";
function Posts({ promessa }: { promessa: Promise<string[]> }) {
const res = use(promessa);
return <div>{res.map(post => post)}</div>;
}
export default function Home() {
const promessa = new Promise<string[]>(resolve => {
setInterval(() => resolve(["Post 1", "Post 2", "Post 3", "Post 4"]), 2000);
});
return (
<div>
<Suspense fallback={<div>carregando...</div>}>
<Posts promessa={promessa} />
</Suspense>
</div>
);
}
Também é possível ler contextos inteiros com essa nova API, o que dispensa o uso do hook useContext
:
import { use } from "react";
import TemaContext from "./TemaContext";
export default function Home({ children }) {
const tema = use(TemaContext);
return (
<div
style={{
color: tema.cor,
}}
>
{children}
</div>
);
}
Melhorias do React 19
Agora, você pode passar referencias (ref
) usando as props, ou seja, não é mais necessário fazer uso do forwardRef
. Antes, para fazermos uso das refs em componentes, nós faríamos assim:
const Input = forwardRef<HTMLInputElement, InputProps>(
({ className, children ...rest }, ref) => {
return (
<input ref={ref} className={className} {...rest}>{children}</input>
)
},
)
Input.displayName = 'Input'
//...
<Input ref={ref} />
Então, apesar da complexidade para iniciante de entender e utilizar o forwardRef
tínhamos que declarar o displayName, caso contrário o React não saberia o nome do componente. Agora, basta passar a ref
por props, como qualquer outra propriedade React:
function Input({placeholder, ref}) {
return <input placeholder={placeholder} ref={ref} />
}
//...
<Input ref={ref} />
Contexto como provedor
Agora, não precisamos mais utilizar <Context.Provider>
para criar provedores de contexto em nossa aplicação, basta envolver a aplicação com o contexto, sem precisar chamar o provider:
const TemaContext = createContext('');
function App({children}) {
return (
<TemaContext value="dark">
{children}
</TemaContext>
);
}
Resumo
O React 19 trouxe muitas novidades, como a adição de novos hooks e melhorias na API, que nos ajudarão a criar aplicações mais leves e performáticas. Além das novidades abordadas neste artigo, existem várias outras melhorias e adições feitas ao React 19 que você pode conferir clicando aqui.