Pular para o conteúdo
Cursos

DevClub

LógicaFront-endBack-endMobile

IA Club

IA na prática
Estudar programaçãoEstudar IA
LiçãoIniciantecódigo testado

Props no React: passar dados de um componente para outro

Como declarar, receber e desestruturar props, definir valor default, passar função e por que alterar uma prop dentro do filho quebra na hora.

Rodolfo Mori12 min de leitura

Imagine cadastrar mil livros numa loja virtual. Se cada cartão tiver título, autor e preço escritos diretamente no componente, você precisará copiar a mesma estrutura mil vezes. Uma correção no layout vira mil correções — e basta esquecer uma para a prateleira ficar inconsistente.

Props resolvem essa repetição: você cria um único cartão e entrega dados diferentes a cada uso. Neste artigo, a livraria cresce do primeiro CardLivro até uma Prateleira real, com preço, destaque e botão de compra.

As tags misturadas ao JavaScript usam JSX, sintaxe que descreve a interface como HTML, a marcação que organiza a página. Se for novo, revise JSX no React e volte sem pressa.

O que são props no React e para que servem?

Props são os valores que um componente React recebe de quem o utiliza. Elas permitem reaproveitar a mesma estrutura com textos, números, objetos e ações diferentes, sem duplicar o componente.

Componente é uma função que descreve parte da interface. Quem usa outro componente é o pai; o usado é o filho. O pai envia as props, e o filho as lê num objeto, valor que reúne informações em pares de nome e conteúdo.

Pense num molde de caixa usado para vários pedidos. A estrutura da caixa é a mesma; a etiqueta informa título, preço e destino. O componente é o molde, e as props são a etiqueta entregue por quem o usa. O limite da analogia é que a caixa é passiva: o componente executa JavaScript e produz uma descrição da tela.

Em <CardLivro titulo="Dom Casmurro" preco={34.9} />, titulo e preco chegam como propriedades de props. Em vez de argumentos separados, o componente recebe esse único objeto.

jsx
import { renderToStaticMarkup } from 'react-dom/server';

function CardLivro(props) {
  return (
    <article className="card-livro">
      <h3>{props.titulo}</h3>
      <p>{props.autor}</p>
      <strong>R$ {props.preco.toFixed(2)}</strong>
    </article>
  );
}

console.log(renderToStaticMarkup(<CardLivro titulo="Dom Casmurro" autor="Machado de Assis" preco={34.9} />));
console.log(renderToStaticMarkup(<CardLivro titulo="Vidas Secas" autor="Graciliano Ramos" preco={42} />));
console.log(renderToStaticMarkup(<CardLivro titulo="Torto Arado" autor="Itamar Vieira Junior" preco={59.9} />));
<article class="card-livro"><h3>Dom Casmurro</h3><p>Machado de Assis</p><strong>R$ 34.90</strong></article> <article class="card-livro"><h3>Vidas Secas</h3><p>Graciliano Ramos</p><strong>R$ 42.00</strong></article> <article class="card-livro"><h3>Torto Arado</h3><p>Itamar Vieira Junior</p><strong>R$ 59.90</strong></article>

O import traz o renderizador do teste. CardLivro recebe props; o return descreve o article; className liga regras visuais de CSS; e as chaves inserem título, autor e preço. toFixed(2) mantém duas casas decimais. Cada log muda o objeto de entrada, e a saída prova: três HTMLs, uma função, nenhuma cópia.

Experimente você mesmo: preveja o segundo cartão

Antes de reler a segunda saída, observe apenas o segundo uso de CardLivro. Preveja título, autor e preço — incluindo as duas casas decimais. Depois confira se a estrutura HTML permaneceu igual e somente os dados mudaram.

Esse objeto de props não é abstração: dá para imprimi-lo inteiro. Cada atributo — nome na abertura da tag — virou uma chave com seu valor.

jsx
function CardLivro(props) {
  console.log(props);
  return <article>{props.titulo}</article>;
}

renderToStaticMarkup(<CardLivro titulo="Dom Casmurro" autor="Machado de Assis" preco={34.9} esgotado={false} />);
{ titulo: 'Dom Casmurro', autor: 'Machado de Assis', preco: 34.9, esgotado: false }

O log mostra o objeto antes do return, que exibe só titulo. A saída confirma as quatro propriedades recebidas. Se algo renderizar errado, inspecionar props revela o que chegou.

Nos testes, Node.js roda JavaScript fora do navegador, esbuild traduz JSX e renderToStaticMarkup produz HTML. Não é preciso memorizar essas ferramentas.

Até aqui, você já sabe: props são um objeto de entrada, o pai escolhe os valores e o mesmo filho produz cartões diferentes sem duplicação.

Como desestruturar props no parâmetro?

Escreva entre chaves os campos que o componente precisa. A desestruturação do JavaScript retira propriedades do objeto e cria variáveis com esses nomes.

Assim, você evita repetir props. sem mudar o valor recebido:

jsx
function CardLivro({ titulo, autor, preco }) {
  return (
    <article className="card-livro">
      <h3>{titulo}</h3>
      <p>{autor}</p>
      <strong>R$ {preco.toFixed(2)}</strong>
    </article>
  );
}

console.log(renderToStaticMarkup(<CardLivro titulo="Dom Casmurro" autor="Machado de Assis" preco={34.9} />));
console.log(renderToStaticMarkup(<CardLivro titulo="Grande Sertão: Veredas" autor="Guimarães Rosa" />));
<article class="card-livro"><h3>Dom Casmurro</h3><p>Machado de Assis</p><strong>R$ 34.90</strong></article> file:///private/tmp/livraria-props/out/desestruturar.mjs:9 preco.toFixed(2) ^

TypeError: Cannot read properties of undefined (reading ‘toFixed’) at CardLivro (file:///private/tmp/livraria-props/out/desestruturar.mjs:9:13) Node.js v24.16.0

Na assinatura, as chaves criam titulo, autor e preco. O retorno usa esses nomes diretamente. O primeiro log passa os três campos e funciona; o segundo omite preco, então essa variável recebe undefined, palavra usada pelo JavaScript para representar a ausência de valor.

Por isso o primeiro card saiu e o segundo parou em preco.toFixed(2): undefined não possui esse método, uma função ligada ao valor. O rastro aponta para o componente, a pista útil para corrigir o problema.

A desestruturação tem um preço pequeno e real: você perde o objeto inteiro. Se quiser os dois, nomeie o resto — function CardLivro({ titulo, ...resto }) — ou fique com props quando o componente tiver muitos campos opcionais e você precisar repassá-los.

Quando usar aspas ou chaves em uma prop?

Use aspas para texto literal e chaves para uma expressão JavaScript. Nas chaves, número continua número, booleano (true ou false) continua booleano e array continua uma lista de valores.

No HTML, atributos costumam chegar como texto. JSX amplia essa possibilidade, mas a diferença visual pode enganar:

jsx
function CardLivro(props) {
  console.log('preco:', props.preco, '| typeof:', typeof props.preco);
  console.log('paginas:', props.paginas, '| typeof:', typeof props.paginas);
  console.log('esgotado:', props.esgotado, '| typeof:', typeof props.esgotado);
  return <article>{props.titulo}</article>;
}

renderToStaticMarkup(<CardLivro titulo="Dom Casmurro" preco="34.90" paginas="256" esgotado="false" />);
console.log('---');
renderToStaticMarkup(<CardLivro titulo="Dom Casmurro" preco={34.9} paginas={256} esgotado={false} />);
preco: 34.90 | typeof: string paginas: 256 | typeof: string esgotado: false | typeof: string --- preco: 34.9 | typeof: number paginas: 256 | typeof: number esgotado: false | typeof: boolean

O componente registra cada prop e usa typeof, operador que informa o tipo do valor. A primeira chamada usa aspas; a segunda usa chaves. Por isso os três primeiros valores são string — texto — e os seguintes são number ou boolean.

Repare que esgotado imprime false nos dois casos, embora sejam valores diferentes. Com aspas, até a formatação do preço quebra:

jsx
function CardLivro({ titulo, preco }) {
  return (
    <article>
      <h3>{titulo}</h3>
      <strong>R$ {preco.toFixed(2)}</strong>
    </article>
  );
}

console.log(renderToStaticMarkup(<CardLivro titulo="Dom Casmurro" preco="34.90" />));
file:///private/tmp/livraria-props/out/aspas-erro.mjs:8 preco.toFixed(2) ^

TypeError: preco.toFixed is not a function at CardLivro (file:///private/tmp/livraria-props/out/aspas-erro.mjs:8:13) Node.js v24.16.0

Repare que a mensagem é diferente da anterior. Cannot read properties of undefined quer dizer “não veio nada”. preco.toFixed is not a function quer dizer “veio alguma coisa, e essa coisa não sabe fazer isso” — no caso, uma string.

O esgotado é pior, porque não quebra: ele mente em silêncio. A string "false" é truthy, tratada como verdadeira numa condição, então qualquer renderização condicional baseada nela dá o resultado invertido.

jsx
function Selo({ esgotado }) {
  return <span>{esgotado && 'ESGOTADO'}</span>;
}

console.log('com aspas: ', renderToStaticMarkup(<Selo esgotado="false" />));
console.log('com chaves:', renderToStaticMarkup(<Selo esgotado={false} />));
com aspas: <span>ESGOTADO</span> com chaves: <span></span>

O livro em estoque apareceu marcado como esgotado. Nenhum erro no console, nenhum aviso: só o cliente desistindo da compra.

Experimente você mesmo: preveja o selo de estoque

Antes de olhar a saída, responda: qual chamada entrega o texto "false", que é truthy, e qual entrega o booleano false, que é falsy, tratado como falso? Agora confira qual delas mostra “ESGOTADO”.

Como passar uma prop booleana sem valor?

Escrever o nome da prop sozinho equivale a passar true. Omitir equivale a não passar nada — e aí ela é undefined, não false:

jsx
function CardLivro({ titulo, destaque }) {
  console.log('destaque:', destaque, '| typeof:', typeof destaque);
  return <article className={destaque ? 'card destaque' : 'card'}>{titulo}</article>;
}

console.log(renderToStaticMarkup(<CardLivro titulo="Torto Arado" destaque />));
console.log(renderToStaticMarkup(<CardLivro titulo="Vidas Secas" />));
destaque: true | typeof: boolean <article class="card destaque">Torto Arado</article> destaque: undefined | typeof: undefined <article class="card">Vidas Secas</article>

Na prática dá no mesmo dentro de um if, porque undefined é falsy. Mas se você comparar com === false, a diferença aparece e o bug custa uma tarde.

Até aqui, você já sabe: aspas criam texto; chaves preservam o tipo; uma prop booleana escrita sozinha vale true; e uma prop omitida vale undefined.

Como definir valor padrão para uma prop?

Use = durante a desestruturação para escolher o valor adotado quando a prop for undefined. Esse valor default, ou padrão, é um recurso de parâmetros do JavaScript, não uma regra exclusiva do React.

Ele evita o primeiro erro deste artigo quando autor ou preço não chegam:

jsx
function CardLivro({ titulo, autor = 'Autor desconhecido', preco = 0 }) {
  return (
    <article className="card-livro">
      <h3>{titulo}</h3>
      <p>{autor}</p>
      <strong>R$ {preco.toFixed(2)}</strong>
    </article>
  );
}

console.log(renderToStaticMarkup(<CardLivro titulo="Grande Sertão: Veredas" />));
console.log(renderToStaticMarkup(<CardLivro titulo="Quarto de Despejo" autor={undefined} preco={29.9} />));
console.log(renderToStaticMarkup(<CardLivro titulo="O Cortiço" autor={null} preco={0} />));
<article class="card-livro"><h3>Grande Sertão: Veredas</h3><p>Autor desconhecido</p><strong>R$ 0.00</strong></article> <article class="card-livro"><h3>Quarto de Despejo</h3><p>Autor desconhecido</p><strong>R$ 29.90</strong></article> <article class="card-livro"><h3>O Cortiço</h3><p></p><strong>R$ 0.00</strong></article>

Compare a segunda linha com a terceira. autor={undefined} recebeu o default; autor={null} não, e o parágrafo saiu vazio. null marca uma ausência intencional; o default só entra para undefined. É a mesma regra dos parâmetros de qualquer função, e é o motivo de um card sair sem nome mesmo com o default no lugar.

Quais valores podem ser passados como props?

Qualquer valor JavaScript pode ser uma prop: texto, número, booleano, array, objeto, JSX ou função. Isso permite entregar tanto dados quanto ações ao filho.

O próximo card recebe um livro, gêneros, uma função que formata o preço e um handler, função executada quando um evento acontece:

jsx
function CardLivro({ livro, generos, formatarPreco, aoAdicionar }) {
  return (
    <article>
      <h3>{livro.titulo} ({livro.ano})</h3>
      <ul>
        {generos.map((g) => <li key={g}>{g}</li>)}
      </ul>
      <strong>{formatarPreco(livro.preco)}</strong>
      <button onClick={aoAdicionar}>Adicionar</button>
    </article>
  );
}

const emReais = (v) => v.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' });

console.log(renderToStaticMarkup(
  <CardLivro
    livro={{ titulo: 'Torto Arado', ano: 2019, preco: 59.9 }}
    generos={['Romance', 'Literatura brasileira']}
    formatarPreco={emReais}
    aoAdicionar={() => console.log('adicionou')}
  />,
));
<article><h3>Torto Arado (2019)</h3><ul><li>Romance</li><li>Literatura brasileira</li></ul><strong>R$ 59,90</strong><button>Adicionar</button></article>

livro fornece título, ano e preço. generos.map transforma cada gênero em li; formatarPreco recebe o número; e onClick guarda aoAdicionar para o botão. A função emReais usa toLocaleString para o formato brasileiro. Na chamada final, cada valor entra entre chaves porque não é texto literal.

Na saída, o espaço entre R$ e 59,90 é U+00A0, usado para o preço não quebrar de linha. O botão não ganha onclick no HTML: React guarda a função e a chama quando o evento acontece. Função passada como prop nunca vira texto publicado.

Como um componente filho envia uma ação ao pai?

O pai passa uma função como prop, e o filho a chama quando a ação acontece. Assim, os dados descem e a intenção volta sem o filho conhecer o carrinho ou a regra do produto.

Este teste cria um DOM com jsdom e dispara o clique com button.click(). DOM é a representação da página manipulada pelo JavaScript. Num projeto com Vite, o navegador já fornece document; o andaime inicial não é necessário.

jsx
import { JSDOM } from 'jsdom';
import { createRoot } from 'react-dom/client';
import { flushSync } from 'react-dom';

const dom = new JSDOM('<div id="raiz"></div>');
globalThis.window = dom.window;
globalThis.document = dom.window.document;

function BotaoComprar({ livro, aoAdicionar }) {
  return <button onClick={() => aoAdicionar(livro)}>Comprar {livro.titulo}</button>;
}

function Prateleira() {
  const carrinho = [];
  const aoAdicionar = (livro) => {
    carrinho.push(livro.titulo);
    console.log('o pai recebeu:', livro.titulo, '| carrinho:', carrinho);
  };
  return (
    <div>
      <BotaoComprar livro={{ titulo: 'Torto Arado' }} aoAdicionar={aoAdicionar} />
      <BotaoComprar livro={{ titulo: 'Vidas Secas' }} aoAdicionar={aoAdicionar} />
    </div>
  );
}

const raiz = createRoot(document.getElementById('raiz'));
flushSync(() => raiz.render(<Prateleira />));

console.log(document.getElementById('raiz').innerHTML);
document.querySelectorAll('button')[1].click(); // clica no segundo botão
<div><button>Comprar Torto Arado</button><button>Comprar Vidas Secas</button></div> o pai recebeu: Vidas Secas | carrinho: [ 'Vidas Secas' ]

Os imports preparam o teste. BotaoComprar recebe livro e função e chama aoAdicionar(livro) no clique. Prateleira possui carrinho, define a ação que inclui o título e a entrega aos dois botões.

createRoot monta a tela; flushSync espera; e [1] escolhe o segundo botão. Assim, “Vidas Secas” chega ao pai. O filho não conhece o carrinho: comunica a intenção, e o pai decide. Esse fluxo sustenta o useState: estado desce como prop e a ação volta como chamada de função.

Até aqui, você já sabe: dados descem como props; uma ação volta como chamada de função. O filho comunica “comprar este livro”, e o pai decide o efeito.

Por que não devemos alterar uma prop no componente filho?

Props são entradas somente de leitura: o pai continua sendo o dono do valor. Se o filho altera esse dado, outros componentes podem enxergar uma versão inconsistente e o fluxo deixa de ter uma origem clara.

O erro aparece quando alguém tenta dar desconto mudando props.preco:

jsx
function CardLivro(props) {
  props.preco = 0; // "dar desconto" mexendo direto na prop
  return <strong>R$ {props.preco.toFixed(2)}</strong>;
}

console.log(renderToStaticMarkup(<CardLivro titulo="Dom Casmurro" preco={34.9} />));
file:///private/tmp/livraria-props/out/somente-leitura.mjs:4 props.preco = 0; ^

TypeError: Cannot assign to read only property ‘preco’ of object ‘#<Object>’ at CardLivro (file:///private/tmp/livraria-props/out/somente-leitura.mjs:4:15) Node.js v24.16.0

Esse erro vem do JavaScript. Em desenvolvimento, React aplica Object.freeze, que congela o objeto. Um módulo ES — arquivo com import ou export — roda em modo estrito, no qual essa alteração lança TypeError. O teste confirma:

jsx
function CardLivro(props) {
  console.log('congelado?', Object.isFrozen(props));
  const precoComDesconto = props.preco * 0.9; // valor novo, prop intacta
  console.log('prop original:', props.preco, '| derivado:', precoComDesconto);
  return <strong>R$ {precoComDesconto.toFixed(2)}</strong>;
}

console.log(renderToStaticMarkup(<CardLivro titulo="Dom Casmurro" preco={34.9} />));
congelado? true prop original: 34.9 | derivado: 31.41 <strong>R$ 31.41</strong>

O caminho é sempre esse: calcule um valor novo, não altere o que chegou. Se o valor precisa mudar de verdade e continuar mudado, ele não era prop — era estado de quem está acima, e a mudança sobe por uma função como a da seção anterior.

Quando usar spread para repassar props?

Use spread entre componentes seus quando o objeto contém exatamente as props esperadas. Evite espalhá-lo diretamente numa tag HTML, pois campos internos podem virar atributos públicos sem intenção.

{...livro} economiza digitação, mas o próximo objeto contém mais dados do que o componente precisa:

jsx
const livro = {
  titulo: 'Torto Arado',
  autor: 'Itamar Vieira Junior',
  preco: 59.9,
  estoque: 12,
  isbn: '9788571373105',
};

function CardLivro({ titulo, autor, preco, ...resto }) {
  return (
    <article {...resto}>
      <h3>{titulo}</h3>
      <p>{autor}</p>
      <strong>R$ {preco.toFixed(2)}</strong>
    </article>
  );
}

console.log(renderToStaticMarkup(<CardLivro {...livro} />));
<article estoque="12" isbn="9788571373105"><h3>Torto Arado</h3><p>Itamar Vieira Junior</p><strong>R$ 59.90</strong></article>

estoque e isbn viraram atributos do HTML publicado. Qualquer pessoa no inspetor vê o estoque. Com camelCase — palavras unidas com maiúsculas no meio — ou objetos aninhados, o vazamento fica mais explícito:

jsx
const livro = {
  titulo: 'Torto Arado',
  precoDeCusto: 31.5,
  fornecedor: { nome: 'Distribuidora Sul' },
};

function CardLivro({ titulo, ...resto }) {
  return <article {...resto}>{titulo}</article>;
}

console.log(renderToStaticMarkup(<CardLivro {...livro} />));
React does not recognize the `precoDeCusto` prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase `precodecusto` instead. If you accidentally passed it from a parent component, remove it from the DOM element. <article precoDeCusto="31.5" fornecedor="[object Object]">Torto Arado</article>

O React avisou, e mesmo assim mandou tudo para o HTML — inclusive o preço de custo e um [object Object] no lugar do fornecedor. Use spread para repassar props entre componentes seus; para o elemento do DOM final, escreva os atributos na mão.

Como escolher bons nomes para props?

Nomeie a prop pela informação ou ação necessária ao componente, não pela origem do dado nem pelo detalhe visual usado hoje. Bons nomes reduzem acoplamento e deixam o componente útil em mais contextos.

Acoplamento é a dependência de uma peça em detalhes de outra. Quanto mais o card sabe sobre API, página ou banco, menos lugares conseguem reaproveitá-lo.

em vez de prefira por quê
<Card livro={livro} /> para exibir dois campos <Card titulo={...} preco={...} /> o componente passa a servir para qualquer coisa que tenha título e preço
<Card corDoFundo="#0f0" /> <Card variante="destaque" /> quem chama escolhe a intenção; o CSS fica com o componente
<Card onClick={...} /> num componente seu <Card aoAdicionar={...} /> onClick promete um evento do DOM; o nome do domínio promete a ação
<Card mostrarBotao={true} escondido={false} /> <Card comBotao /> duas booleanas que se contradizem geram quatro estados, e dois deles não existem

A regra é: a prop diz o que o componente precisa saber, nunca de onde o dado veio. titulo é bom; tituloDaApi amarra o card à origem e deixa de servir quando o campo vier de outro lugar.

Juntando tudo, a prateleira fica assim — o pai lê o catálogo, escolhe o que cada card precisa e passa item por item:

jsx
const catalogo = [
  { id: 1, titulo: 'Torto Arado', autor: 'Itamar Vieira Junior', preco: 59.9, destaque: true },
  { id: 2, titulo: 'O Cortiço', autor: 'Aluísio Azevedo', preco: 24.5, destaque: false },
];

function CardLivro({ titulo, autor, preco, destaque = false }) {
  return (
    <article className={destaque ? 'card destaque' : 'card'}>
      <h3>{titulo}</h3>
      <p>{autor}</p>
      <strong>R$ {preco.toFixed(2)}</strong>
    </article>
  );
}

function Prateleira({ titulo, livros }) {
  return (
    <section>
      <h2>{titulo}</h2>
      {livros.map((livro) => (
        <CardLivro
          key={livro.id}
          titulo={livro.titulo}
          autor={livro.autor}
          preco={livro.preco}
          destaque={livro.destaque}
        />
      ))}
    </section>
  );
}

console.log(renderToStaticMarkup(<Prateleira titulo="Literatura brasileira" livros={catalogo} />));
<section><h2>Literatura brasileira</h2><article class="card destaque"><h3>Torto Arado</h3><p>Itamar Vieira Junior</p><strong>R$ 59.90</strong></article><article class="card"><h3>O Cortiço</h3><p>Aluísio Azevedo</p><strong>R$ 24.50</strong></article></section>

catalogo guarda dois livros. CardLivro recebe apenas os quatro valores que usa; o default de destaque é false, e o ternário escolhe a classe CSS. Prateleira recebe título e livros, cria um card por item com map e passa cada prop de forma explícita. A última linha monta a seção e produz o HTML da saída.

O key não é uma prop comum: ele não chega no objeto de props do CardLivro. É um dado que o React usa para identificar cada item da lista renderizada com map.

O caminho mínimo → produto está completo: começamos com um card que recebe três valores e terminamos com uma prateleira que distribui dados de catálogo para vários componentes, sem copiar sua estrutura.

Até aqui, você já sabe: props configuram componentes, preservam tipos entre chaves, aceitam funções, não devem ser alteradas e precisam expor apenas o que o filho realmente usa.

O que estudar depois de props no React?

A próxima lição é renderização condicional no React: ela mostra como props como esgotado e destaque decidem o que aparece. Depois, a trilha passa por listas e eventos até o useState, que guarda valores mutáveis. Mais adiante, a trilha de TypeScript ensina o editor a avisar sobre tipos antes da execução. O guia de React mostra a sequência completa.

Prefere aprender em vídeo?

Tem uma aula sobre este assunto no nosso canal.

Ver todos os vídeos do canal
  • react
  • props
  • componentes
  • desestruturacao

Perguntas frequentes

Qual a diferença entre props e state?
Props vêm de fora e o componente não pode mudá-las. State nasce dentro do componente e existe justamente para mudar. Quando um valor precisa mudar por causa de um clique, ele é state de alguém — e desce como prop para quem só precisa exibir.
Como levar uma prop até o neto sem passar pelo filho?
Passar de mão em mão por vários níveis chama-se prop drilling. As duas saídas são composição (o pai monta o conteúdo e entrega via children) e a Context API, que publica o valor para toda a subárvore.
Preciso declarar quais props o componente aceita?
Em JavaScript puro, não: qualquer atributo vira propriedade do objeto de props. O React 19 removeu o PropTypes do pacote, então a checagem de tipo hoje é trabalho do TypeScript.
Posso passar um componente inteiro como prop?
Pode. JSX é valor, então <CardLivro rodape={<BotaoComprar />} /> é legítimo e é a base dos componentes de layout, que recebem pedaços de tela prontos e só decidem onde encaixar.

Dúvidas e comentários

Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.

Todo o código deste artigo foi executado em Node 24.16.0 com React 19.2.8, e as saídas exibidas são as reais — como produzimos este conteúdo.

Fontes consultadas

  1. React — Passando props para um componente — pt-br.react.dev
  2. React 19 — Removed: propTypes — react.dev
  3. MDN — Atribuição via desestruturação — developer.mozilla.org

Continue por aqui