React: Componentes de função e props
Última atualização: 2026-10-26
Os componentes de função são como peças de Lego — cada peça tem sua própria forma (props) e pode ser montada e combinada de várias maneiras. Os props são as “interfaces” das peças: seja qual for a cor ou o tamanho que você atribuir à peça, é assim que ela ficará.
1. O que você vai aprender
- Definição e convenções de nomenclatura para componentes de função
- Passar e receber adereços
- Tipos de propriedades (string / número / booleano / objeto)
- adereço especial para crianças
- Use o TypeScript para anotar os tipos das propriedades
2. Uma história real de uma equipe de front-end
Fluxo de dados entre componentes e props
flowchart TD
A[Parent Component] -->|"name='Alice'"| B[UserCard]
A -->|"items=[...]"| C[ProductList]
C -->|"item={...}"| D[ProductCard]
B -->|"children"| E[<Avatar />]
A -->|"onFollow callback"| B
style A fill:#e3f2fd,stroke:#1565c0
style B fill:#e8f5e9,stroke:#2e7d32
style C fill:#fff3e0,stroke:#e65100
style D fill:#fce4ec,stroke:#c62828
(1) Problema: Um botão que você precisa copiar e colar 50 vezes
Charlie é o líder técnico de uma equipe de front-end. Ele descobriu que havia mais de 50 botões diferentes espalhados por 20 páginas no repositório de código:
// Page A:Red Button
<button style={{ backgroundColor: 'red', color: 'white' }}>
Delete
</button>
// Page B:Blue Button
<button style={{ backgroundColor: 'blue', color: 'white' }}>
Submit
</button>
// Page C:Small gray button
<button style={{ backgroundColor: 'gray', color: 'black', fontSize: '12px' }}>
Cancel
</button>
Pergunta:
- Alterações no design: Todos os botões precisam ter cantos arredondados; isso exige alterações em 50 lugares.
- Inconsistência: Alguns botões usam
red, outros usam#ff0000e outros ainda usamrgb(255,0,0) - Erros frequentes: Alguém definiu o estilo incorretamente, fazendo com que o botão inteiro ficasse transparente
(2) Uma abordagem baseada em componentes
Gerenciamento unificado por meio de componentes de função e props:
function Button({ variant = 'primary', size = 'medium', children }) {
const styles = {
primary: { backgroundColor: '#1890ff', color: 'white' },
danger: { backgroundColor: '#ff4d4f', color: 'white' },
default: { backgroundColor: '#f0f0f0', color: '#333' }
}
return (
<button style={{
...styles[variant],
padding: size === 'large' ? '12px 24px' : '8px 16px',
border: 'none',
borderRadius: '6px',
cursor: 'pointer'
}}>
{children}
</button>
)
}
// Usage:Done in one line of code
<Button variant="danger">Delete</Button>
<Button variant="primary">Submit</Button>
<Button variant="default">Cancel</Button>
Benefícios: O número de botões foi reduzido de 50 fragmentos para 1 componente; agora, as alterações no design exigem apenas uma modificação, garantindo um estilo consistente.
3. Fundamentos dos componentes de função
(1) Definição de um componente
No React, um componente de função é uma função em JavaScript que retorna JSX.
// The Simplest Function Component
function Welcome() {
return <h1>Hello, React!</h1>
}
// How to Write Arrow Functions(More common)
const Welcome = () => {
return <h1>Hello, React!</h1>
}
// Implicit Return(Only one line JSX "when " can be omitted return)
const Welcome = () => <h1>Hello, React!</h1>
| Regra | Descrição |
|---|---|
| Colocar a primeira letra em maiúscula | Welcome ✅ welcome ❌ (O React distingue entre componentes e tags HTML) |
| Retornar JSX | Deve retornar um elemento JSX (ou null) |
| Funções puras | A mesma entrada (Props) deve retornar a mesma saída (UI) |
| Props não podem ser modificadas | As props são somente para leitura e não podem ser modificadas dentro do componente |
(2) Os props são argumentos de função
Props (abreviação de “Properties”) são dados somente para leitura passados de um componente pai para um componente filho.
// ---- Define a Component ----
function Greeting(props) {
// props It is an object,Includes all incoming parameters
return <h1>Hello,{props.name}!This year, you {props.age} years old。</h1>
}
// ---- Using Components ----
<Greeting name="Alice" age={28} />
// Rendering Results:
// <h1>Hello,Alice!This year, you 28 years old。</h1>
(3) Sintaxe de desestruturação para props
Uma abordagem mais comum é a atribuição desconstrutiva, que recupera diretamente os parâmetros desejados:
// Deconstructive Writing Style(Recommendations)
function Greeting({ name, age }) {
return <h1>Hello,{name}!This year, you {age} years old。</h1>
}
// equivalent to:
function Greeting(props) {
const { name, age } = props
return <h1>Hello,{name}!This year, you {age} years old。</h1>
}
4. Tipos de adereços
| Tipo de prop | Sintaxe de passagem | Exemplo de recepção | Observações |
|---|---|---|---|
| String | name="Alice" |
{ name } → “Alice” |
Entre aspas duplas |
| Número | age={30} |
{ age } → 30 |
É necessário usar {} |
| Booleano | active / active={true} |
{ active } → verdadeiro |
Se o valor for omitido, o padrão é verdadeiro |
| Objeto | info={{ key: 'val' }} |
{ info } → { key: 'val' } |
Chaves duplas |
| Matriz | items={[1, 2, 3]} |
{ items } → [1,2,3] |
É necessário usar {} |
| Função | onClick={handler} |
{ onClick } → fn |
Callback/Manipulador de eventos |
| Componente | icon={<Icon />} |
{ icon } → JSX |
Componente renderizado dinamicamente |
Os props podem aceitar qualquer tipo de dados em JavaScript: strings, números, valores booleanos, objetos, matrizes, funções e até mesmo outros componentes.
(1) String
As sequências de caracteres podem ser passadas diretamente usando aspas duplas (assim como os atributos HTML):
function UserCard({ name, role }) {
return (
<div className="card">
<h2>{name}</h2>
<p>Characters:{role}</p>
</div>
)
}
// Strings are enclosed in double quotes,For other types {} Package
<UserCard name="Alice" role="Administrator" />
(2) Números, valores booleanos e objetos
Os tipos que não sejam de cadeia de caracteres devem ser colocados entre {}:
function Product({ name, price, inStock, details }) {
return (
<div className="product">
<h3>{name}</h3>
<p>Price:${price}</p>
{/* Boolean values are used for conditional rendering */}
{inStock ? <span>In stock ✅</span> : <span>Out of stock ❌</span>}
{/* Object:Accessible properties */}
<p>Category:{details.category} | Weight:{details.weight}g</p>
</div>
)
}
// Using Components
<Product
name="Wireless Mouse"
price={89}
inStock={true}
details={{ category: 'Peripherals', weight: 120 }}
/>
Saída:
Formulário com campos de entrada e tratamento de envio
(3) Tabela de referência rápida para métodos de passagem por valor
| Tipo | Exemplo | Descrição |
|---|---|---|
| String | name="Alice" |
Escrito da mesma forma que os atributos HTML |
| Número | count={42} |
Requer {} |
| Valor booleano true | active ou active={true} |
Se apenas o nome da propriedade for especificado, o valor padrão é true |
| Valor booleano falso | active={false} |
Requer {} |
| Objeto | data={{ x:1, y:2 }} |
Chaves duplas |
| Matriz | items={[1,2,3]} |
Requer {} |
| Expressão | result={a + b} |
Qualquer expressão em JS |
| Variável | name={userName} |
Variável passada por valor |
▶ Exemplo: Cartão de informações do usuário
// ============================================
// Example:use Props Build a User Information Card
// Features:Display Props Transmission of Various Types
// ============================================
function UserCard({ name, age, isOnline, avatar, tags }) {
return (
<div style={{
border: '1px solid #ddd',
borderRadius: '8px',
padding: '20px',
maxWidth: '300px'
}}>
<img
src={avatar}
alt={name}
style={{ width: '80px', height: '80px', borderRadius: '50%' }}
/>
<h2>{name}</h2>
<p>Age:{age} years old</p>
<p>
Status:
<span style={{ color: isOnline ? '#52c41a' : '#999' }}>
{isOnline ? 'Online' : 'Offline'}
</span>
</p>
<div>
Tags:
{tags.map(tag => (
<span key={tag} style={{
background: '#f0f0f0',
padding: '2px 8px',
borderRadius: '4px',
margin: '0 4px',
fontSize: '12px'
}}>
{tag}
</span>
))}
</div>
</div>
)
}
// Using Components
<UserCard
name="Alice"
age={28}
isOnline={true}
avatar="https://i.pravatar.cc/80"
tags={['Front End', 'React', 'TypeScript']}
/>
Saída:
Cartão de usuário: avatar, "Alice", "28 anos", status "Online" (verde), tags: [Front End] [React] [TypeScript]
5. Elementos filhos e valores padrão
(1) filhos: conteúdo aninhado dentro do componente
children é um Prop especial que representa o conteúdo entre as tags de componente.
// Definition:use children Content between tags
function Card({ children, title }) {
return (
<div style={{ border: '1px solid #ddd', padding: '16px', borderRadius: '8px' }}>
<h3>{title}</h3>
<div>{children}</div> {/* The content between the tags is displayed here */}
</div>
)
}
// Usage:The content between the tags automatically becomes children
<Card title="Announcement">
<p>The system will go live tonight 22:00 Perform maintenance,Expected to continue 2 hours。</p>
<p>Please save your work in advance.,To prevent data loss。</p>
</Card>
// Rendering Results:
// <div class="card">
// <h3>Announcement</h3>
// <div>
// <p>The system will go live tonight 22:00 Perform maintenance...</p>
// <p>Please save your work in advance....</p>
// </div>
// </div>
(2) Valor padrão
Use a sintaxe de desestruturação do ES6 com valores padrão para definir valores padrão para as propriedades:
function Button({ text = 'Click', color = 'blue', size = 'medium' }) {
return (
<button style={{
backgroundColor: color,
padding: size === 'large' ? '12px 24px' : '8px 16px',
color: 'white',
border: 'none',
borderRadius: '4px'
}}>
{text}
</button>
)
}
// No parameters → Use the default values
<Button /> // Blue、medium、"Click"
// Pass some parameters → Override the default value
<Button text="Submit" /> // Blue、medium、"Submit"
<Button color="red" size="large" /> // Red、large、"Click"
6. Anotações de tipo no TypeScript (Visão geral)
Usando o TypeScript, é possível definir tipos rigorosos para as props, permitindo que o editor ofereça sugestões de autocompletar e realize verificações de tipo:
// ---- Definition Props Type ----
interface ButtonProps {
text: string // Required:string
color?: string // Optional: add ? suffix
size?: 'small' | 'medium' | 'large' // Optional: limited to 3 values
onClick: () => void // Required:Function Types
disabled?: boolean // Optional: boolean, defaults to false
}
// ---- Using in a component ----
function Button({ text, color = 'blue', size = 'medium', onClick, disabled = false }: ButtonProps) {
return (
<button
onClick={onClick}
disabled={disabled}
style={{
backgroundColor: color,
padding: size === 'large' ? '12px 24px' : '8px 16px',
opacity: disabled ? 0.5 : 1,
color: 'white',
border: 'none',
borderRadius: '4px'
}}
>
{text}
</button>
)
}
// Usage:The editor provides smart suggestions
<Button
text="Save"
color="#1890ff"
size="medium"
onClick={() => alert('Saved successfully!')}
/>
// ❌ Error:TypeScript It will throw an error
<Button text="Test" /> // Required field is missing onClick
<Button text="Test" size="xl" onClick={fn} /> // size Outside the permitted range
7. Exemplo completo: Componente “Ficha do produto”
// ============================================
// Example:Product Card Component(Comprehensive Application Props Various Types)
// ============================================
// Type Definitions
interface Product {
id: number
name: string
price: number
image: string
category: string
tags: string[]
}
interface ProductCardProps {
product: Product
onAddToCart: (productId: number) => void
showDiscount?: boolean
size?: 'small' | 'large'
}
// Component Implementation
function ProductCard({
product,
onAddToCart,
showDiscount = false,
size = 'large'
}: ProductCardProps) {
return (
<div style={{
border: '1px solid #eee',
borderRadius: '8px',
padding: size === 'large' ? '16px' : '10px',
width: size === 'large' ? '280px' : '200px'
}}>
<img
src={product.image}
alt={product.name}
style={{ width: '100%', height: '150px', objectFit: 'cover' }}
/>
<h3>{product.name}</h3>
<p style={{ color: '#ff4d4f', fontSize: '20px', fontWeight: 'bold' }}>
${product.price}
{showDiscount && <span style={{ fontSize: '12px', color: '#999', textDecoration: 'line-through', marginLeft: '8px' }}>${(product.price * 1.2).toFixed(0)}</span>}
</p>
<p style={{ color: '#666', fontSize: '14px' }}>{product.category}</p>
<div>
{product.tags.map(tag => (
<span key={tag} style={{ background: '#f0f5ff', color: '#1890ff', padding: '2px 6px', borderRadius: '4px', margin: '0 2px', fontSize: '12px' }}>
{tag}
</span>
))}
</div>
<button
onClick={() => onAddToCart(product.id)}
style={{
width: '100%',
padding: '8px',
marginTop: '10px',
backgroundColor: '#1890ff',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}}
>
Add to Cart
</button>
</div>
)
}
// Using Components
const myProduct = {
id: 101,
name: 'Mechanical Keyboard',
price: 299,
image: 'https://via.placeholder.com/280x150',
category: 'Computer Peripherals',
tags: ['Hot Seller', 'New Products']
}
<ProductCard
product={myProduct}
onAddToCart={(id) => console.log('Add to Cart:', id)}
showDiscount={true}
/>
Saída:
Subtítulo: "{name}". Exibe: "Status:"
Resultado esperado: Uma ficha de produto exibindo a imagem de um teclado, o nome “Teclado Mecânico”, o preço de US$ 299 (com o preço original de US$ 359 riscado), a categoria “Periféricos de computador” e as tags “Mais vendido” e “Novidade”, com um botão azul “Adicionar ao carrinho” abaixo.
▶ Exemplo 2: Uso abrangente da passagem de tipos de props e valores padrão
// ============================================
// Example:Profile Card——Props Combined Use of Types and Default Values
// Features:Display string、number、boolean、object、function etc. Props Type Passing
// ============================================
function ProfileCard({
name = 'Anonymous User',
age = 0,
isActive = false,
avatar = 'https://via.placeholder.com/60',
skills = [],
onGreet
}) {
return (
<div style={{
border: '1px solid #e8e8e8',
borderRadius: '12px',
padding: '20px',
maxWidth: '320px',
boxShadow: '0 2px 8px rgba(0,0,0,0.06)'
}}>
<div style={{ display: 'flex', alignItems: 'center', gap: '16px', marginBottom: '16px' }}>
<img
src={avatar}
alt={name}
style={{ width: '60px', height: '60px', borderRadius: '50%', objectFit: 'cover' }}
/>
<div>
<h3 style={{ margin: 0 }}>{name}</h3>
<p style={{ margin: '4px 0 0 0', color: '#666', fontSize: '14px' }}>
{age} years old · {isActive ? '🟢 Online' : '🔴 Offline'}
</p>
</div>
</div>
{skills.length > 0 && (
<div style={{ marginBottom: '12px' }}>
<p style={{ margin: '0 0 8px 0', fontWeight: 'bold', fontSize: '14px' }}>Skills:</p>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '6px' }}>
{skills.map((skill, index) => (
<span key={index} style={{
backgroundColor: '#f0f5ff',
color: '#1890ff',
padding: '4px 10px',
borderRadius: '12px',
fontSize: '12px'
}}>
{skill}
</span>
))}
</div>
</div>
)}
{onGreet && (
<button
onClick={() => onGreet(name)}
style={{
width: '100%',
padding: '8px',
backgroundColor: '#1890ff',
color: 'white',
border: 'none',
borderRadius: '6px',
cursor: 'pointer',
fontSize: '14px'
}}
>
Say hello to {name}
</button>
)}
</div>
)
}
// Usage:Pass all parameters
<ProfileCard
name="Alice"
age={28}
isActive={true}
avatar="https://i.pravatar.cc/60"
skills={['React', 'TypeScript', 'Node.js']}
onGreet={(name) => alert(`Hello,${name}!`)}
/>
// Usage:Pass only some parameters(Use the default values for the rest)
<ProfileCard
name="Bob"
skills={['Vue', 'Python']}
/>
// Usage:Do not pass any parameters(Use all default values)
<ProfileCard />
Saída:
Perfil de Alice: avatar, "28 anos · 🟢 Online", habilidades [React][TypeScript][Node.js], botão "Say hello to Alice" → alert("Hello, Alice!")
Saída:
Exibe "products". Estado: adding, cart. Botão: {adding ? 'adding...' : `add ${productname}`}
▶ Exemplo 3: Props de callback de eventos — Componentes filhos notificando componentes pais
▶ ExperimenteSaída:
"Add Keyboard" botão → "Adding...", depois o carrinho exibe "Keyboard". Botão "Add Mouse" → carrinho: "Keyboard, Mouse". Carrinho vazio mostra "empty".
Saída:
Subtítulo: "Products". Exibe: "Products". Estado: adding (setter: setAdding), cart (setter: setCart). Botão: {adding ? 'Adding...' : `Add ${productName}`}. Busca assíncrona de dados / estados de carregamento
▶ Exemplo 4: Renderização condicional de props — Troca dinâmica de componentes
▶ ExperimenteSaída:
⏳ Loading... (azul) / ✅ Success! (verde) / ❌ Error occurred (vermelho) / 📭 No data (cinza). Os botões alternam o status.
Saída:
Exibe "users"
▶ Exemplo 5: O padrão renderProps — Componentes de lista e renderização personalizada
function DataList({ items, renderItem, keyExtractor, emptyMessage = 'No items' }) {
if (!items || items.length === 0) {
return <p style={{ color: '#999', textAlign: 'center', padding: 20 }}>{emptyMessage}</p>
}
return (
<ul style={{ listStyle: 'none', padding: 0 }}>
{items.map(item => (
<li key={keyExtractor(item)} style={{ borderBottom: '1px solid #f0f0f0', padding: 8 }}>
{renderItem(item)}
</li>
))}
</ul>
)
}
function App() {
const users = [
{ id: 1, name: 'Alice', email: 'alice@example.com', active: true },
{ id: 2, name: 'Bob', email: 'bob@example.com', active: false },
{ id: 3, name: 'Charlie', email: 'charlie@example.com', active: true },
]
const products = [
{ id: 'a', name: 'Keyboard', price: 79 },
{ id: 'b', name: 'Monitor', price: 399 },
]
return (
<div style={{ maxWidth: 400, margin: '0 auto' }}>
<h3>Users</h3>
<DataList
items={users}
keyExtractor={u => u.id}
renderItem={u => (
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<span>{u.name} ({u.email})</span>
<span style={{ color: u.active ? '#52c41a' : '#999' }}>
{u.active ? 'Active' : 'Inactive'}
</span>
</div>
)}
/>
<h3>Products</h3>
<DataList
items={products}
keyExtractor={p => p.id}
emptyMessage="No products available"
renderItem={p => (
<span>{p.name} - ${p.price}</span>
)}
/>
</div>
)
}
Saída:
Users: Alice (alice@example.com, Active), Bob (bob@example.com, Inactive), Charlie (charlie@example.com, Active)
Products: Keyboard - $79, Monitor - $399
❓ Perguntas Frequentes
<div> é uma tag div do HTML; <Div> é um componente personalizado. Se um componente for escrito em minúsculas, o React o tratará como uma tag HTML, fazendo com que a renderização falhe.function Card({ title = 'Untitled' }) {}; ② Usar Card.defaultProps = { title: 'Untitled' }. Observe que o React não recomenda mais o uso de defaultProps (em componentes de função); recomenda-se usar a desestruturação para atribuir valores padrão. No TypeScript, você também pode usar title?: string para indicar que uma propriedade é opcional, o que torna o código mais claro quando combinado com a desestruturação para atribuir valores padrão.📖 Resumo
- Um componente de função é uma função JavaScript que retorna JSX; a primeira letra deve estar em maiúscula
- Props são dados somente para leitura passados de um componente pai para um componente filho; o componente filho não pode modificá-los.
- Os parâmetros podem ser de qualquer tipo: string, número, booleano, objeto, array ou função
childrené um Prop especial que representa o conteúdo entre as tags de componente- Use a sintaxe de desestruturação
function Comp({ prop1, prop2 })para tornar seu código mais claro - As anotações de tipo do TypeScript podem melhorar significativamente a experiência de desenvolvimento e a robustez do código
📝 Exercícios
- Problema básico (Dificuldade ⭐): Crie um componente
Avatarque aceite duas propriedades —name(uma string) esize(um número, com valor padrão 50) — e exiba o avatar e o nome do usuário. - Problema avançado (Dificuldade ⭐⭐): Crie um componente
TagListque aceite duas propriedades —tags(um array de strings) eonRemove(uma função) — e exiba uma lista de tags. Ao clicar em uma tag, ela é excluída. - Desafio (Dificuldade ⭐⭐⭐): Crie um componente
DataTableem TypeScript que aceitecolumns(um array de definições de colunas) edata(um array de dados) e exiba uma tabela de dados simples. Tente adicionar uma propriedadestriped(booleano, opcional) para controlar o padrão zebra.