"Revisão de React Forms, Data Fetching e Routing"
---
id: 67c9e932c6c4234532d46394
title: "Revisão de React Forms, Data Fetching e Routing"
challengeType: 31
dashedName: review-react-forms-data-fetching-and-routing
---
# --description--
Trabalhando com o Hook
Trabalhando com o Hook
Trabalhando com o Hook
Trabalhando com o Hook
Trabalhando com Formulários em React
- Controlled Inputs: Isso acontece quando você armazena o valor do campo de entrada no estado e o atualiza através de eventos
onChange. Isso lhe dá controle completo sobre os dados do formulário e permite validação instantânea e renderização condicional.
import { useState } from "react";
function App() {
const [name, setName] = useState("");
const handleChange = (e) => {
setName(e.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
console.log(name);
};
return (
<>
<form onSubmit={handleSubmit}>
<label htmlFor="name">Your name</label> <br />
<input value={name} id="name" onChange={handleChange} type="text" />
<button type="submit">Submit</button>
</form>
</>
);
}
export default App;
- Entradas Não Controladas: Em vez de manipular as entradas através do hook
useState, entradas não controladas em HTML mantêm seu próprio estado interno com a ajuda do DOM. Como o DOM controla os valores das entradas, você precisa obter os valores dos campos de entrada com umref.
import { useRef } from "react";
function App() {
const nameRef = useRef();
const handleSubmit = (e) => {
e.preventDefault();
console.log(nameRef.current.value);
};
return (
<form onSubmit={handleSubmit}>
<label htmlFor="name">Your</label>{" "}
<input type="text" ref={nameRef} id="name" />
<button type="submit">Submit</button>
</form>
);
}
export default App;
Trabalhando com o Hook useActionState
- Server Actions: Estas são funções que são executadas no servidor para permitir o manuseio de formulários diretamente no servidor sem a necessidade de endpoints de API. Aqui está um exemplo de uma aplicação Next.js:
"use server";
async function submitForm(formData) {
const name = formData.get("name");
return { message: Hello, ${name}! };
}
A diretiva "user server" marca a função como uma ação do servidor.
- Hook
useActionState: Este hook atualiza o estado com base no resultado de uma submissão de formulário. Aqui está a sintaxe básica do hookuseActionState:
const [state, action, isPending] = useActionState(actionFunction, initialState, permalink);
stateé o estado atual que a ação retorna.actioné a função que dispara a ação do servidor.isPendingé um booleano que indica se a ação está sendo executada no momento ou não.- O parâmetro
actionFunctioné a própria ação do servidor. initialStateé o parâmetro que representa o ponto de partida para o estado antes da execução da ação.permalinké uma string opcional que contém a URL única da página que o formulário modifica.
Busca de Dados em React
- Opções Para Buscar Dados: Existem muitas maneiras diferentes de buscar dados no React. Você pode usar a Fetch API nativa ou ferramentas de terceiros como Axios ou SWR.
- Variáveis de Estado Comumente Usadas ao Buscar Dados: Independentemente da forma que você escolher para buscar seus dados em React, existem alguns pedaços de estado que você precisará acompanhar. O primeiro é o próprio dado. O segundo acompanhará se os dados ainda estão sendo buscados. O terceiro é uma variável de estado que capturará quaisquer erros que possam ocorrer durante o processo de busca dos dados.
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
Como a obtenção de dados é um efeito colateral, é melhor usar a Fetch API dentro de um hook useEffect.
useEffect(() => {
const fetchData = async () => {
try {
const res = await fetch("https://jsonplaceholder.typicode.com/posts");
if (!res.ok) {
throw new Error("Network response was not ok");
}
const data = await res.json();
setData(data);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
Então você pode exibir uma mensagem de carregamento se a busca dos dados não estiver completa, uma mensagem de erro se houve um erro ao buscar os dados, ou os resultados.
if (loading) {
return <p>Loading...</p>;
}
if (error) {
return <p>{error.message}</p>;
}
return (
<ul>
{data.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
Se você quiser usar Axios, você precisa instalá-lo e importá-lo:
npm i axios
import axios from "axios";
Então você pode buscar os dados usando axios.get:
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const res = await axios.get(
"https://jsonplaceholder.typicode.com/users"
);
setData(res.data);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
Para buscar dados usando o hook useSWR, você precisa primeiro instalá-lo e importá-lo.
npm i swr
import useSWR from "swr";
Aqui está como você pode usar o hook para buscar dados:
import useSWR from "swr";
const fetcher = (url) => fetch(url).then((res) => res.json());
const FetchTodos = () => {
const { data, error } = useSWR(
"https://jsonplaceholder.typicode.com/todos",
fetcher
);
if (!data) {
return <h2>Loading...</h2>;
}
if (error) {
return <h2>Error: {error.message}</h2>;
}
return (
<>
<h2>Todos</h2>
<div>
{data.map((todo) => (
<h3 key={todo.id}>{todo.title}</h3>
))}
</div>
</>
);
};
export default FetchTodos;
Trabalhando com o Hook useOptimistic
- Hook
useOptimistic: Este hook é usado para manter as UIs responsivas enquanto aguarda a conclusão de uma ação assíncrona em segundo plano. Ele ajuda a gerenciar "atualizações otimistas" na UI, uma estratégia na qual você fornece atualizações imediatas para a UI com base no resultado esperado de uma ação, como aguardar uma resposta do servidor.
const [optimisticState, addOptimistic] = useOptimistic(actualState, updateFunction);
optimisticStateé o estado temporário que é atualizado imediatamente para uma melhor experiência do usuário.addOptimisticé a função que aplica a atualização otimista antes das mudanças reais no estado.actualStateé o valor real do estado que vem do resultado de uma ação, como buscar dados de um servidor.updateFunctioné a função que determina como o estado otimista deve ser atualizado quando chamada.
useOptimistic em um componente TaskList:
"use client";
import { useOptimistic } from "react";
export default function TaskList({ tasks, addTask }) {
const [optimisticTasks, addOptimisticTask] = useOptimistic(
tasks,
(state, newTask) => [...state, { text: newTask, pending: true }]
);
async function handleSubmit(e) {
e.preventDefault();
const formData = new FormData(e.target);
addOptimisticTask(formData.get("task"));
addTask(formData);
e.target.reset();
}
return <>{/* UI */}</>;
}
startTransition: Isso é usado para renderizar parte da UI e marcar uma atualização de estado como uma transição não urgente. Isso permite que a UI seja responsiva durante atualizações custosas. Aqui está a sintaxe básica:
startTransition(action);
A action executa uma atualização de estado ou dispara alguma lógica relacionada à transição. Isso garante que atualizações urgentes da UI (como digitar ou clicar) não sejam bloqueadas.
Trabalhando com o Hook useMemo
- Memoization: Esta é uma técnica de otimização na qual o resultado de chamadas de função custosas é armazenado em cache (lembrado) com base em argumentos específicos. Quando os mesmos argumentos são fornecidos novamente, o resultado em cache é retornado em vez de recalcular a função.
- Hook
useMemo: Este hook é usado para memorizar valores computados. Aqui está um exemplo de como memorizar o resultado da ordenação de um array grande. AexpensiveSortFunctionserá executada apenas quandolargeArraymudar:
const memoizedSortedArray = useMemo(
() => expensiveSortFunction(largeArray),
[largeArray]
);
Trabalhando com o Hook useCallback
- Hook
useCallback: Isso é usado para memorizar referências de função.
const handleClick = useCallback(() => {
// code goes here
}, [dependency]);
React.memo: Isso é usado para memorizar um componente para evitar re-renderizações desnecessárias quando sua prop não mudou.
const MemoizedComponent = React.memo(({ prop }) => {
return (
<>
{/* Presentation */}
</>
)
});
Ferramentas de Gerenciamento de Dependências
- Definição de Dependência: Em software, uma dependência é quando um componente ou módulo em uma aplicação depende de outro para funcionar corretamente. Dependências são comuns em aplicações de software porque permitem que desenvolvedores usem funções ou ferramentas pré-construídas criadas por outros. As duas dependências principais necessárias para um projeto React serão os pacotes
reactereact-dom:
"dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1"
}
- Definição de Gerenciador de Pacotes: Para gerenciar dependências de software em um projeto, você precisará usar um gerenciador de pacotes. Um gerenciador de pacotes é uma ferramenta usada para instalação, atualizações e remoção de dependências. Muitas linguagens de programação populares como JavaScript, Python, Ruby e Java usam gerenciadores de pacotes. Gerenciadores de pacotes populares para JavaScript incluem
npm,Yarnepnpm. - Arquivo
package.json: Este é um arquivo de configuração chave em projetos que contém metadados sobre seu projeto, incluindo seu nome, versão e dependências. Ele também define scripts, informações de licenciamento e outras configurações que ajudam a gerenciar o projeto e suas dependências. - Arquivo
package-lock.json: Este arquivo irá travar as versões exatas de todos os pacotes que seu projeto está usando. Quando você atualizar um pacote, as novas versões também serão atualizadas no arquivo de bloqueio. - Pasta
node_modules: Esta pasta contém o código real das dependências listadas no seu arquivopackage.json, incluindo tanto as dependências diretas do seu projeto quanto quaisquer dependências dessas dependências. - Dependências de Desenvolvimento: Estes são pacotes que são usados apenas para desenvolvimento e não em produção. Um exemplo disso seria uma biblioteca de testes como o Jest. Você instalaria o Jest como uma dependência de desenvolvimento porque ele é necessário para testar sua aplicação localmente mas não é necessário para que a aplicação funcione em produção.
"devDependencies": {
"@eslint/js": "^9.17.0",
"@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5",
"@vitejs/plugin-react": "^4.3.4",
"eslint": "^9.17.0",
"eslint-plugin-react": "^7.37.2",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.16",
"globals": "^15.14.0",
"vite": "^6.0.5"
}
React Router
- Introdução: React Router é uma biblioteca de terceiros que permite adicionar roteamento às suas aplicações React. Para começar, você precisará instalar o React Router em um projeto React existente assim:
npm i react-router
Então, dentro do arquivo main.jsx ou index.jsx, você precisará configurar a estrutura de rotas assim:
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { BrowserRouter, Routes, Route } from "react-router";
import App from "./App.jsx";
import "./index.css";
createRoot(document.getElementById("root")).render(
<StrictMode>
<BrowserRouter>
<Routes>
<Route path="/" element={<App />} />
</Routes>
</BrowserRouter>
</StrictMode>
);
O path e o element são usados para acoplar a URL e os componentes da interface do usuário juntos. Neste caso, estamos configurando uma rota para a página inicial que aponta para o componente App.
- Múltiplas Views e Configuração de Rotas: É comum em aplicações maiores ter múltiplas views e configurações de rotas assim:
<Routes>
<Route index element={<Home />} />
<Route path="about" element={<About />} />
<Route path="products">
<Route index element={<ProductsHome />} />
<Route path=":category" element={<Category />} />
<Route path=":category/:productId" element={<ProductDetail />} />
<Route path="trending" element={<Trending />} />
</Route>
</Routes>
A prop index nesses exemplos tem o propósito de representar a rota padrão para um determinado segmento de caminho. Então o componente Home será exibido na rota raiz / enquanto o componente ProductsHome será exibido na rota /products.
- Rotas Aninhadas: Você pode aninhar rotas dentro de outras rotas o que resulta no caminho da rota filha sendo anexado ao caminho da rota pai.
<Route path="products">
<Route path="trending" element={<Trending />} />
</Route>
No exemplo acima, o caminho para os produtos em alta será products/trending.
- Segmentos Dinâmicos: Um segmento dinâmico é onde qualquer parte do caminho da URL é dinâmica.
<Route path=":category" element={<Category />} />
Neste exemplo temos um segmento dinâmico chamado category. Quando um usuário navega para uma URL como products/brass-instruments, a visualização mudará para o componente Category e você pode buscar dinamicamente os dados apropriados com base no segmento.
- Hook
useParams: Este hook é usado para acessar os parâmetros dinâmicos de um caminho de URL.
import { useParams } from "react-router";
export default function Category() {
let params = useParams();
{/* Accessing the category param: params.category */}
{/* rest of code goes here */}
}
Frameworks React
- Introdução: Frameworks React fornecem recursos como roteamento, otimizações de imagem, busca de dados, autenticação e mais. Isso significa que você pode não precisar configurar aplicações front-end e back-end separadas para certos casos de uso. Exemplos de Frameworks React incluem Next.js e Remix.
- Next.js Routing: Este sistema de roteamento inclui suporte para rotas dinâmicas, rotas paralelas, manipuladores de rotas, redirecionamentos, internalização e mais.
export async function GET() {
const res = await fetch("https://example-api.com");
const data = await res.json();
return Response.json({ data });
}
- Otimização de Imagens no Next.js: O componente
Imageestende o elemento nativo HTMLimge permite carregamentos de página mais rápidos e otimizações de tamanho. Isso significa que as imagens serão carregadas apenas quando entrarem na área visível e o componenteImageservirá automaticamente imagens com o tamanho correto para cada dispositivo.
import Image from "next/image";
export default function Page() {
return (
<Image src="link-to-image-goes-here" alt="descriptive-title-goes-here" />
);
}
Prop Drilling
- Definição: Prop drilling é o processo de passar props de um componente pai para componentes filhos profundamente aninhados, mesmo quando alguns dos componentes filhos não precisam dos props.
Gerenciamento de Estado
- Context API: Contexto refere-se a quando um componente pai disponibiliza informações para componentes filhos sem a necessidade de passá-las explicitamente através de props.
createContexté usado para criar um objeto de contexto que representa o contexto que outros componentes irão ler. OProvideré usado para fornecer valores de contexto aos componentes filhos.
import { useState, createContext } from "react";
const CounterContext = createContext();
const CounterProvider = ({ children }) => {
const [count, setCount] = useState(0);
return (
<CounterContext.Provider value={{ count, setCount }}>
{children}
</CounterContext.Provider>
);
};
export { CounterContext, CounterProvider };
- Redux: Redux handles state management by providing a central store and strict control over state updates. Ele usa um padrão previsível com actions, reducers e middleware. Ações são cargas úteis de informação que enviam dados da sua aplicação para o
Redux store, frequentemente acionadas por interações do usuário. Reducers são funções que especificam como o estado deve mudar em resposta a essas ações, garantindo que o estado seja atualizado de forma imutável. Middleware, on the other hand, acts as a bridge between the action dispatching and the reducer, allowing you to extend Redux's functionality (e.g., logging, handling async operations) without modifying the core flow. - Zustand: Esta solução de gerenciamento de estado é ideal para aplicações de pequeno a médio porte. Ela funciona usando um hook
useStorepara acessar o estado diretamente em componentes e páginas. Isso permite modificar e acessar dados sem a necessidade de actions, reducers ou um provider.
Depuração de Componentes React Usando o React DevTools
- React Developer Tools: Esta é uma extensão de navegador que você pode usar no Chrome, Firefox e Edge para inspecionar componentes React e identificar problemas de desempenho. Para Safari, você precisará instalar o pacote npm
react-devtools. Após instalar o React DevTools e abrir um app React no navegador, abra as ferramentas de desenvolvedor do navegador para acessar as duas abas extras fornecidas para depuração do React – Components e Profiler. - Aba Components: Esta aba exibe cada componente para você em um formato de visualização em árvore. Aqui estão algumas coisas que você pode fazer nesta aba:
- visualize a hierarquia de componentes do app
- verifique e modifique
props,statese valores decontextem tempo real - verifique o código-fonte de cada componente selecionado
- registre os dados do componente no console
- inspecione os elementos DOM para o componente
- Aba Profiler: Esta aba ajuda você a analisar o desempenho dos componentes. Você pode registrar o desempenho dos componentes para identificar re-renderizações desnecessárias, visualizar durações de commits e, subsequentemente, otimizar componentes lentos.
Componentes de Servidor React
- Definição: React Server Components são componentes React que renderizam exclusivamente no servidor, enviando apenas o HTML final para o cliente. Isso significa que esses componentes podem acessar diretamente recursos do lado do servidor e reduzir drasticamente a quantidade de JavaScript enviada para o navegador.