Este procedimento deve ser realizado somente se você possuir uma branch remota no repositório do que esta sendo apresentado. Caso não possua clique em next.
Guia de Configuração e Execução do Projeto
Siga o passo a passo abaixo para clonar, configurar o ambiente com Git Flow e executar o projeto localmente.
git clone <endereço-remoto-repositorio>
cd nome do repositório
git branch
git branch -a
Inicia a estrutura do Git Flow no projeto e muda automaticamente para a branch develop:
git flow init
Atenção (PC da Instituição): Caso o Git Flow não esteja instalado no Windows, execute:
winget install GitTower.GitFlowNext
git switch <nomeDaBranch>
# ou
git checkout <nomeDaBranch>
cd my-app
ls
code .
exit
No VS Code, abra um novo terminal usando o Command Prompt (CMD) e instale as dependências:
npm install
# ou
npm i
Atenção: Certifique-se de que o terminal está dentro da pasta my-app.
npm run dev
Antes de iniciar a codificação, certifique-se de que seu repositório local está sincronizado com a branch de referência.
git clone <endereco-remoto-repositorio>
cd my-app
git branch -a
Se você precisa iniciar exatamente do ponto oficial ou corrigir problemas locais:
# Baixar dados atualizados
git fetch origin
# Caso vá criar sua branch nova a partir do professor:
git switch -c feature/exemplo-rmSeuRM origin/feature/exemplo-pf0670
# OU caso precise resetar sua branch atual para o estado oficial:
git reset --hard origin/feature/exemplo-pf0670
npm install
npm run dev
id: fundamentos-react-hooks summary: Guia Definitivo: Componentes, Props, Hooks e Renderização Condicional categories: react, frontend tags: fiap, frontend status: Published authors: TDS Professor
Fundamentos do React: Componentes, Props e Hooks
Um componente funcional é uma função comum do JavaScript que tem apenas uma regra principal: ela precisa retornar um código visual (HTML/JSX).
Em vez de construir uma página inteira de uma vez, você cria pequenos pedaços isolados (como um botão, um cabeçalho ou um cartão) e junta todos eles depois.
Aqui criamos um componente chamado CartaoCyberpunk. Ele é apenas uma função que retorna uma div estilizada.
export default function CartaoCyberpunk() {
return (
<div style={{
backgroundColor: '#0d0d0d',
border: '2px solid #39ff14',
padding: '20px',
color: '#39ff14'
}}>
<h2>Acesso ao Sistema</h2>
<p>Terminal ativado com sucesso.</p>
</div>
);
}
Como usar? Para colocar esse componente na sua tela principal, você o importa e o escreve como se fosse uma tag HTML normal: .
Props (abreviação de propriedades) são informações que você envia de fora para dentro de um componente.
Se você criar um componente de botão, não faz sentido escrever o texto dele fixo no código, senão todos os botões do seu site terão o mesmo texto. As props resolvem isso permitindo que você passe valores diferentes toda vez que usar o componente.
Vamos modificar o cartão anterior para receber um titulo e uma mensagem via props.
// 1. Definimos o que o componente vai receber
interface CartaoProps {
titulo: string;
mensagem: string;
}
// 2. Recebemos as props usando a desestruturação { titulo, mensagem }
export default function CartaoDinamico({ titulo, mensagem }: CartaoProps) {
return (
<div style={{ border: '2px solid #ff00ff', padding: '20px', color: '#ff00ff' }}>
<h2>{titulo}</h2>
<p>{mensagem}</p>
</div>
);
}
Como usar? Ao chamar o componente na tela principal, você entrega as informações assim:
Hook (que significa "gancho") é uma função especial nativa do React.
Como os componentes funcionais são apenas funções simples de JavaScript, eles não têm memória e não sabem quando a tela muda. Os Hooks servem para "enganchar" recursos extras nessas funções simples, como dar a elas uma memória interna ou a capacidade de observar mudanças.
Regra de ouro: Todo Hook obrigatoriamente começa com a palavra use (exemplo: useState, useEffect).
O useState é a memória do componente. Ele guarda um valor que pode mudar com o tempo. A grande vantagem é: toda vez que o valor do
useState
muda, o React atualiza a tela automaticamente para mostrar o novo valor.
import { useState } from 'react';
export default function Contador() {
// 1. Criamos a memória.
// 'numero' é o valor atual. 'setNumero' é a única função que pode alterar esse valor.
// O (0) significa que o número começa em zero.
const [numero, setNumero] = useState(0);
function aumentar() {
setNumero(numero + 1); // Avisa o React para mudar o valor e atualizar a tela
}
return (
<div>
<p>Tentativas de login: {numero}</p>
<button onClick={aumentar}>Tentar Novamente</button>
</div>
);
}
O useEffect é um observador. Ele serve para executar um pedaço de código em momentos específicos, geralmente em duas situações:
import { useState, useEffect } from 'react';
export default function Monitor() {
const [status, setStatus] = useState('Aguardando...');
// O useEffect roda a função interna toda vez que a variável 'status' mudar.
useEffect(() => {
// Ação: Mudar o título da aba do navegador
document.title = `Sistema: ${status}`;
}, [status]); // O array [status] é a lista de dependências (o que ele está vigiando).
return (
<div>
<p>Status atual: {status}</p>
<button onClick={() => setStatus('Conectado')}>Conectar</button>
</div>
);
}
O useParams faz parte do pacote react-router. Ele serve para capturar valores dinâmicos que o usuário digitou no endereço do navegador (URL).
Se você tem uma rota configurada como /usuario/:id, o useParams captura o que foi digitado no lugar do :id.
Se o usuário acessar o endereço http://seusite.com/usuario/993...
import { useParams } from 'react-router';
export default function PerfilUsuario() {
// O hook extrai a parte móvel da URL e guarda na variável 'id'
const { id } = useParams<{ id: string }>();
return (
<div>
<h1>Perfil do Usuário</h1>
<p>Você está acessando os dados do usuário número: {id}</p>
</div>
);
}
O useRef serve para selecionar e interagir com um elemento HTML físico na tela, de forma direta. É o equivalente moderno de usar o antigo document.getElementById().
Ele guarda a referência daquela tag HTML, permitindo que você aplique ações diretas, como dar foco em um campo de texto ou ler a largura de uma imagem.
import { useRef } from 'react';
export default function Formulario() {
// 1. Criamos a referência vazia
const inputNome = useRef<HTMLInputElement>(null);
function focarNoCampo() {
// 3. Acessamos o elemento físico (.current) e aplicamos a ação de foco (.focus())
inputNome.current?.focus();
}
return (
<div>
{/* 2. Conectamos a referência diretamente na tag HTML usando ref={} */}
<input type="text" ref={inputNome} placeholder="Digite seu nome" />
<button onClick={focarNoCampo}>Focar no Campo</button>
</div>
);
}
O useLocation também pertence ao react-router. Ele lê e retorna os dados do endereço atual exato em que o usuário está no momento. Diferente do useParams (que pega apenas uma variável específica), o useLocation pega o caminho inteiro.
Se o usuário estiver no endereço http://seusite.com/configuracoes/rede...
import { useLocation } from 'react-router';
export default function RastreadorRota() {
// Captura o objeto completo com os dados da URL atual
const local = useLocation();
return (
<div>
<p>O caminho completo que você está acessando é: {local.pathname}</p>
{/* O resultado escrito na tela será: /configuracoes/rede */}
</div>
);
}
Nota técnica: A ação de redirecionar o usuário via código no React Router é feita pelo hook useNavigate.
O useNavigate serve para trocar a tela do usuário através de um comando no código, sem que ele precise clicar em um link padrão. É muito usado após o preenchimento de um formulário ou após um login bem-sucedido.
import { useNavigate } from 'react-router';
export default function TelaLogin() {
// 1. Inicializa o hook de navegação
const navegar = useNavigate();
function fazerLogin() {
// Aqui aconteceria a verificação de senha...
// 2. Se a senha estiver correta, redireciona o usuário para o painel principal
navegar('/painel');
}
return (
<div>
<button onClick={fazerLogin}>Entrar no Sistema</button>
</div>
);
}
O operador ternário é um atalho para o if/else tradicional. No React, usamos o ternário dentro do HTML (JSX) para exibir uma informação ou outra dependendo de uma condição (renderização condicional).
A estrutura é dividida em três partes: Condição ? Exibe isso se for Verdade : Exibe isso se for Falso
import { useState } from 'react';
export default function PainelAcesso() {
const [logado, setLogado] = useState(false);
return (
<div style={{ backgroundColor: '#1a1a1a', padding: '20px' }}>
{/* Lógica Ternária sendo aplicada diretamente no visual */}
{logado ? (
<h2 style={{ color: '#39ff14' }}>Acesso Liberado: Bem-vindo!</h2>
) : (
<h2 style={{ color: '#ff003c' }}>Acesso Negado: Faça Login.</h2>
)}
{/* Botão que inverte o valor de verdadeiro para falso e vice-versa */}
<button onClick={() => setLogado(!logado)}>
Trocar Status
</button>
</div>
);
}
Nesta etapa, vamos transformar nossa aplicação em um sistema com múltiplas telas. Utilizaremos o react-router para ensinar o React a trocar de página sem precisar recarregar o navegador do zero.
Abra o terminal na pasta do seu projeto e execute o comando abaixo para instalar a biblioteca de roteamento:
npm i react-router
O que fizemos aqui? O comando i é a abreviação de install. A biblioteca react-router funciona como o "GPS" da nossa aplicação. É ela quem mapeia qual componente deve ser exibido na tela dependendo do endereço (URL) que o usuário digitar.
Dentro da sua pasta src, crie uma nova pasta chamada routes. Dentro dela, crie as subpastas e os arquivos exatamente como no esquema abaixo:
src/
└── routes/
├── Home/index.tsx
├── Produtos/index.tsx
├── EditarProdutos/index.tsx
└── Error/index.tsx
Por que estruturar assim?
/routes: Separa o que é uma "Página inteira" do que é apenas um "Componente" (como um botão ou cabeçalho).index.tsx: Usar esse nome faz com que o arquivo seja o padrão da pasta. Assim, ao importar a rota, basta chamar o nome da pasta e o sistema já sabe que deve carregar o index.tsx.Adicione uma função básica dentro de cada arquivo index.tsx criado, apenas para termos o que renderizar. Por exemplo, no Home/index.tsx:
export default function Home() {
return <h1>Página Inicial</h1>;
}
main.tsx)O arquivo main.tsx é o coração do projeto. Vamos configurá-lo para ser o gerente das nossas rotas. Substitua o conteúdo atual por este:
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { createBrowserRouter, RouterProvider } from 'react-router';
// Importação das nossas páginas
import App from './App';
import Home from './routes/Home';
import Produtos from './routes/Produtos';
import EditarProdutos from './routes/EditarProdutos';
import Error from './routes/Error';
// 1. Criando o mapa de rotas
const router = createBrowserRouter([
{
path: "/",
element: <App />,
errorElement: <Error />,
children: [
{ path: "/", element: <Home /> },
{ path: "/produtos", element: <Produtos /> },
{ path: "/editar-produtos", element: <EditarProdutos /> }
]
}
]);
// 2. Injetando o roteador na aplicação
createRoot(document.getElementById('root')!).render(
<StrictMode>
<RouterProvider router={router} />
</StrictMode>
);
Dissecando o código:
createBrowserRouter: É a função que memoriza todas as URLs válidas do nosso site.path: É o endereço digitado no navegador (ex: /produtos).element: Qual tela deve aparecer quando esse endereço for acessado.errorElement: A famosa "Página 404". Aparece caso o usuário digite um caminho que não existe.children: São as sub-rotas. Elas vão ser injetadas "dentro" do componente .RouterProvider: O componente provedor que substitui a chamada direta do , conectando o mapa de rotas que criamos (o router) diretamente à raiz do React.App.tsx)Agora precisamos preparar o nosso componente raiz (App.tsx) para receber e trocar as telas filhas.
import { Outlet, Link } from 'react-router';
export default function App() {
return (
<>
<header>
<nav>
<Link to="/">Início</Link> |
<Link to="/produtos">Produtos</Link>
</nav>
</header>
{/* Onde a mágica acontece */}
<Outlet />
<footer>
<p>© Sistema de Produtos</p>
</footer>
</>
);
}
Um dado "mockado" é um dado fictício. Como ainda não temos um banco de dados real ou uma API conectada à internet, vamos criar uma lista manual para simular o que o servidor nos devolveria.
Crie o arquivo e adicione a lista expandida abaixo:
import { TipoProduto } from '../types/types';
export const listaProdutos: TipoProduto[] = [
{
id: 1,
nome: "Headset Gamer Sem Fio",
preco: 299.90,
descricao: "Áudio espacial 7.1 e microfone retrátil.",
avatar: "https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=120&auto=format&fit=crop&q=80"
},
{
id: 2,
nome: "Teclado Mecânico RGB",
preco: 249.00,
descricao: "Switches mecânicos rápidos.",
avatar: "https://images.unsplash.com/photo-1587829741301-dc798b83add3?w=120&auto=format&fit=crop&q=80"
},
{
id: 3,
nome: "Mouse Gamer Sem Fio",
preco: 150.00,
descricao: "Sensor óptico de alta precisão e bateria de longa duração.",
avatar: "https://images.unsplash.com/photo-1527814050087-379381547969?w=120&auto=format&fit=crop&q=80"
},
{
id: 4,
nome: "Monitor Ultrawide 29\"",
preco: 1200.00,
descricao: "Tela IPS com taxa de atualização de 75Hz e HDR10.",
avatar: "https://images.unsplash.com/photo-1527443224154-c4a3942d3acf?w=120&auto=format&fit=crop&q=80"
},
{
id: 5,
nome: "Cadeira Gamer Ergonômica",
preco: 850.00,
descricao: "Apoio lombar ajustável e inclinação de até 180° graus.",
avatar: "https://images.unsplash.com/photo-1598550476439-6847785fcea6?w=120&auto=format&fit=crop&q=80"
},
{
id: 6,
nome: "Webcam Full HD 1080p",
preco: 199.90,
descricao: "Foco automático e microfone embutido com redutor de ruído.",
avatar: "https://images.unsplash.com/photo-1621259182978-fbf93132d53d?w=120&auto=format&fit=crop&q=80"
}
];
O que fizemos aqui?
import { TipoProduto }: Trouxemos o "molde" que criamos no passo anterior.TipoProduto[]: O uso dos colchetes [] avisa ao TypeScript que não estamos criando apenas um produto, mas sim uma lista (um Array) composta por vários itens que seguem a mesma regra.src/routes/Produtos/index.tsx)Agora vamos conectar a nossa lista de mentirinha com a tela do navegador. Abra o componente de Produtos e substitua pelo código abaixo:
import { useState, useEffect } from 'react';
import { Link } from 'react-router';
import { TipoProduto } from '../../types/types';
import { listaProdutos } from '../../data/listaProdutos';
export default function Produtos() {
// 1. Criando a "gaveta de memória" do componente
const [produtos, setProdutos] = useState<TipoProduto[]>([]);
// 2. Disparando a busca de dados ao carregar a página
useEffect(() => {
setProdutos(listaProdutos);
}, []);
return (
<main style={{ padding: '20px' }}>
<h1>Painel de Produtos</h1>
{/* 3. Estruturando a tabela */}
<table border={1} cellPadding={10} style={{ width: '100%', borderCollapse: 'collapse' }}>
{/* Cabeçalho das colunas */}
<thead>
<tr style={{ backgroundColor: '#2c3e50', color: '#ffffff' }}>
<th>Foto</th>
<th>ID</th>
<th>Nome</th>
<th>Preço</th>
<th>Ações</th>
</tr>
</thead>
{/* 4. Corpo da Tabela: Gerando as linhas dinamicamente */}
<tbody>
{produtos.map((item) => (
<tr key={item.id}>
<td>
<img
src={item.avatar}
alt={item.nome}
width={60}
height={60}
style={{ objectFit: 'cover' }}
/>
</td>
<td>{item.id}</td>
<td>{item.nome}</td>
<td>R$ {item.preco.toFixed(2)}</td>
<td>
{/* 5. Link dinâmico passando o ID na URL */}
<Link to={`/editar-produtos/${item.id}`}>Editar</Link>
</td>
</tr>
))}
</tbody>
</table>
</main>
);
}
Dissecando o código passo a passo:
useState (O Estado): Atua como a memória da tela. Começamos com uma lista vazia ([]). A função setProdutos é a única autorizada a colocar informações dentro dessa memória e, quando ela faz isso, o React redesenha a tela automaticamente.useEffect (O Observador): O array vazio [] no final diz ao React: "Execute isso apenas uma vez, assim que o componente aparecer na tela". É aqui que ele vai na listaProdutos e guarda na nossa memória. (O Visual): Criamos a estrutura clássica de tabela com para a linha de títulos e para acomodar os dados.
- 4.
.map() (A Linha de Montagem): Essa função percorre a nossa lista. Para cada produto que ela encontra, ela constrói uma linha da tabela ().
- Atenção: O atributo
key={item.id} é obrigatório no React. Ele usa esse ID único para não se perder caso você precise apagar ou reordenar um produto depois.
- 5. O
Dinâmico: Em vez de direcionar para um endereço fixo, usamos a crase (Template String) para juntar o caminho padrão com a variável do ID do produto atual. Se clicarmos no Mouse, ele nos levará para /editar-produtos/3.
Até agora, nossas rotas eram estáticas (o endereço exato precisava ser digitado, como /produtos). Agora, configuraremos uma rota dinâmica, ou seja, uma tela que muda dependendo do ID do produto que passamos na URL.
1. Atualizar o Roteador no src/main.tsx
Abra o seu arquivo de rotas principal e altere a definição da rota de edição. Adicionaremos o identificador variável :id ao final do caminho:
// Procure a lista de rotas (children) e substitua a rota antiga por esta:
{ path: "/editar-produtos/:id", element: <EditarProdutos /> }
O que significa o símbolo
:
na rota? O uso dos dois pontos (:) avisa ao React Router que a palavra id não é um texto fixo, mas sim um coringa (um espaço em branco). Se o usuário digitar /editar-produtos/5 ou /editar-produtos/99 no navegador, o roteador vai aceitar e entender que 5 e 99 são, na verdade, o valor do nosso :id.
2. Entendendo a Desestruturação (Destructuring)
Antes de recuperar esse valor no componente, precisamos entender uma técnica moderna do JavaScript chamada Desestruturação (Destructuring).
O hook useParams sempre devolve um objeto contendo todos os parâmetros da URL. Em vez de guardar o objeto inteiro em uma variável para depois tirar a informação de dentro dele, a desestruturação permite "abrir" o objeto e pegar apenas o que queremos logo de cara.
// ❌ JEITO TRADICIONAL (Sem destructuring)
const parametros = useParams(); // Retorna o objeto inteiro: { id: "99" }
const meuId = parametros.id; // Extrai o valor do objeto
// ✅ JEITO MODERNO (Com destructuring)
// Lemos assim: "Vá no objeto que o useParams retornou e arranque apenas a propriedade 'id' de dentro dele".
const { id } = useParams();
3. Recuperando o Parâmetro no Componente (EditarProdutos/index.tsx)
Agora que a rota está preparada para receber o dado e já sabemos como extraí-lo com destructuring, vamos aplicar isso na tela de edição:
// 1. Importamos o hook que lê os parâmetros da URL
import { useParams } from 'react-router';
export default function EditarProdutos() {
// 2. Extraímos o "id" usando destructuring e tipamos como string
const { id } = useParams<{ id: string }>();
return (
<main style={{ padding: '20px' }}>
<h1>Editar Produto</h1>
<p>Identificador recebido pela rota: <strong>{id}</strong></p>
</main>
);
}
Como o
useParams
consegue pegar o que foi digitado? A mágica acontece em 3 passos invisíveis:
- O usuário acessa:
http://localhost:5173/editar-produtos/42.
- O Roteador lê: O
react-router analisa essa URL e cruza com o mapa que criamos lá no main.tsx (/editar-produtos/:id).
- O Roteador guarda: Ele percebe que o número
42 está exatamente na posição onde deveria estar o curinga :id. Ele empacota isso em um objeto interno parecido com { id: "42" }.
- O Hook captura: Quando chamamos o
useParams() dentro do componente, ele funciona como uma antena que se conecta a esse pacote criado pelo roteador, trazendo o valor 42 para podermos usar no nosso HTML.