Etapa 2 — Comunicação entre componentes (Props, State e Eventos)
Bem-vindo(a) à etapa onde o React começa a ficar interativo. Aqui você vai aprender como os componentes conversam entre si e como a interface reage às ações do usuário.
1) Props — passando dados do pai para o filho
O que são?
Props (propriedades) são dados que o componente pai envia para o componente filho.
Dentro do filho, as props são somente leitura (imutáveis).
1.1 Exemplo básico
// Botao.jsx
export default function Botao(props) {
return <button>{props.texto}</button>;
}
// App.jsx
import Botao from "./Botao";
export default function App() {
return (
<div>
<h1>Exemplo de Props</h1>
<Botao texto="Clique aqui" />
<Botao texto="Enviar formulário" />
</div>
);
}
1.2 Desestruturação (mais comum no dia a dia)
export default function Botao({ texto }) {
return <button>{texto}</button>;
}
1.3 Tipos comuns de props
- string/number/boolean:
<Preco valor={19.9} /> - array/objeto:
<Lista itens={['a','b']} /> - funções (callbacks):
<Form onSubmit={handleSubmit} /> - elementos/JSX pelo
children:<Card><p>Conteúdo</p></Card>
1.4 Children prop (componente “embrulhador”)
// Card.jsx
export default function Card({ children }) {
return <div className="card">{children}</div>;
}
// App.jsx
<Card>
<h2>Título</h2>
<p>Qualquer conteúdo aqui dentro vai para o children.</p>
</Card>
1.5 Passando funções via props (filho → aciona algo no pai)
// Produto.jsx (filho)
export default function Produto({ nome, onAdicionar }) {
return (
<div>
<span>{nome}</span>
<button onClick={onAdicionar}>Adicionar</button>
</div>
);
}
// App.jsx (pai)
import { useState } from "react";
import Produto from "./Produto";
export default function App() {
const [quantidade, setQuantidade] = useState(0);
function adicionarAoCarrinho() {
setQuantidade(q => q + 1);
}
return (
<div>
<h1>Carrinho: {quantidade}</h1>
<Produto nome="Teclado" onAdicionar={adicionarAoCarrinho} />
<Produto nome="Mouse" onAdicionar={adicionarAoCarrinho} />
</div>
);
}
Por que isso é importante? Props levam dados e funções para baixo na árvore. Quando o filho precisa “avisar” algo ao pai, ele chama a função recebida por props.
2) State — valores que mudam com o tempo
O que é?
O state é a memória interna de um componente. Quando o state muda, o React re-renderiza e a interface é atualizada.
2.1 Sintaxe básica com useState
import { useState } from "react";
export default function Contador() {
const [numero, setNumero] = useState(0); // 0 = valor inicial
return (
<div>
<p>Você clicou {numero} vezes</p>
<button onClick={() => setNumero(numero + 1)}>Clique</button>
</div>
);
}
2.2 Atualização baseada no valor anterior (forma segura)
setNumero((anterior) => anterior + 1);
Use essa forma quando a atualização depender do valor anterior. Evita bugs com atualizações em lote.
2.3 Não mutar o state diretamente
Errado (objeto):
estado.usuario.nome = "Ana"; // não faça isso setEstado(estado); // não dispara re-render corretamenteCerto (cópia imutável):
setEstado(prev => ({ ...prev, usuario: { ...prev.usuario, nome: "Ana" } }));Listas (adicionar/remover/editar)
// adicionar setItens(prev => [...prev, novoItem]); // remover setItens(prev => prev.filter(item => item.id !== id)); // editar setItens(prev => prev.map(it => it.id === id ? { ...it, nome: "Novo" } : it));
2.4 Inputs controlados (state + input)
import { useState } from "react";
export default function Formulario() {
const [nome, setNome] = useState("");
function handleSubmit(e) {
e.preventDefault(); // evita reload da página
alert(`Olá, ${nome}!`);
}
return (
<form onSubmit={handleSubmit}>
<input
value={nome}
onChange={(e) => setNome(e.target.value)}
placeholder="Digite seu nome"
/>
<button type="submit">Enviar</button>
</form>
);
}
2.5 Lifting state up (subir o estado para o pai)
Quando dois ou mais componentes precisam do mesmo dado, mova o state para o ancestral comum e passe props para os filhos.
// Filtro.jsx (filho - apenas emite eventos)
export default function Filtro({ termo, onChange }) {
return (
<input
value={termo}
onChange={(e) => onChange(e.target.value)}
placeholder="Filtrar produtos"
/>
);
}
// Lista.jsx (filho - recebe dados filtrados)
export default function Lista({ itens }) {
return (
<ul>
{itens.map((p) => <li key={p.id}>{p.nome}</li>)}
</ul>
);
}
// App.jsx (pai - guarda o state compartilhado)
import { useState } from "react";
import Filtro from "./Filtro";
import Lista from "./Lista";
const TODOS = [
{ id: 1, nome: "Teclado" },
{ id: 2, nome: "Mouse" },
{ id: 3, nome: "Monitor" },
];
export default function App() {
const [termo, setTermo] = useState("");
const filtrados = TODOS.filter(p =>
p.nome.toLowerCase().includes(termo.toLowerCase())
);
return (
<div>
<Filtro termo={termo} onChange={setTermo} />
<Lista itens={filtrados} />
</div>
);
}
3) Eventos — reagindo a ações do usuário
3.1 Eventos mais usados
onClick— clique em botão/elementoonChange— mudança em inputsonSubmit— envio de formulárioonKeyDown,onKeyUp,onMouseEnter, etc.
3.2 Exemplos práticos
<button onClick={() => alert("Clicou!")}>Clique</button>
Passando parâmetros para o handler:
function remover(id) {
console.log("remover", id);
}
<button onClick={() => remover(42)}>Remover item 42</button>
Formulário com preventDefault:
function handleSubmit(e) {
e.preventDefault();
// ...enviar dados
}
<form onSubmit={handleSubmit}>...</form>
3.3 Dica: nomeie callbacks que vêm por props com onAlgo
// Filho
export default function Item({ id, nome, onRemover }) {
return <button onClick={() => onRemover(id)}>Remover {nome}</button>;
}
// Pai
<Item id={7} nome="Mouse" onRemover={handleRemover} />
4) Exemplo integrado (props + state + eventos)
// ContadorComPasso.jsx
import { useState } from "react";
export default function ContadorComPasso({ passoInicial = 1 }) {
const [valor, setValor] = useState(0);
const [passo, setPasso] = useState(passoInicial);
return (
<div>
<h3>Valor: {valor}</h3>
<label>
Passo:
<input
type="number"
value={passo}
onChange={(e) => setPasso(Number(e.target.value) || 0)}
/>
</label>
<div>
<button onClick={() => setValor(v => v + passo)}>+ {passo}</button>
<button onClick={() => setValor(v => v - passo)}>- {passo}</button>
<button onClick={() => setValor(0)}>Zerar</button>
</div>
</div>
);
}
// App.jsx
import ContadorComPasso from "./ContadorComPasso";
export default function App() {
return (
<div>
<h1>Demo: Props + State + Eventos</h1>
<ContadorComPasso passoInicial={2} />
<ContadorComPasso passoInicial={5} />
</div>
);
}
5) Erros comuns (e como evitar)
Espaço nas rotas/links gerando
%20
Useto="/states"(sem espaço antes).Mutação direta do state (não re-renderiza corretamente)
Sempre crie cópias ({ ...obj },[...array]).Atualização baseada no valor anterior sem função
PrefirasetX(prev => prev + 1)quando depender do valor anterior.Esquecer
keyao renderizar listasitens.map(item => <li key={item.id}>{item.nome}</li>)Inputs “descontrolados”
Lembre de passarvalue+onChangequando quiser controlar o campo via state.
6) Exercícios rápidos
- Crie um componente Botao que receba as props
textoeonClick, e use-o várias vezes no App. - Faça um contador com botões de
+1e-1usandouseState. - Crie um formulário controlado com campos
nomeeemailque exibe os valores abaixo do form em tempo real. - Faça um componente Produto (filho) com botão “Adicionar”, que chama uma função no App (pai) para aumentar o total do carrinho.
- Implemente um filtro de lista: um input no pai e uma lista de itens filtrados no filho (use lifting state up).
Para onde ir depois?
- Renderização condicional (
cond ? <A/> : <B/>econd && <A/>) - useEffect para buscar dados de API
- Context API para evitar prop drilling quando muitos níveis precisam do mesmo dado
Dominando props, state e eventos, você já consegue criar interfaces reativas, controlar formulários e fazer componentes realmente reutilizáveis.