Variações de Sintaxe de Componentes de Função
Todas as formas de escrever um componente de função React - declaração vs. expressão, arrow vs. function, export padrão vs. export nomeado, e quando cada forma importa.
Busque em todas as páginas da documentação
Todas as formas de escrever um componente de função React - declaração vs. expressão, arrow vs. function, export padrão vs. export nomeado, e quando cada forma importa.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Cartão de receita de referência rápida.
// 1. Declaração de função (mais comum)
function Greeting({ name }: { name: string }) {
return <h1>Olá, {name}</h1>;
}
// 2. Função Arrow atribuída a const
const Greeting = ({ name }: { name: string }) => {
return <h1>Olá, {name}</h1>;
};
// 3. Função Arrow com retorno implícito
const Greeting = ({ name }: { name: string }) => (
<h1>Olá, {name}</h1>
);
// 4. Export padrão - declaração de função
export default function Greeting({ name }: { name: string }) {
return <h1>Olá, {name}</h1>;
}
// 5. Export padrão - função Arrow (duas etapas)
const Greeting = ({ name }: { name: string }) => (
<h1>Olá, {name}</h1>
);
export default Greeting;
// 6. Export nomeado
export function Greeting({ name }: { name: string }) {
return <h1>Olá, {name}</h1>;
}
// 7. Export nomeado - função Arrow
export const Greeting = ({ name }: { name: string }) => (
<h1>Olá, {name}</h1>
);Quando usar isso: Você não precisa escolher um estilo exclusivamente - mas deve entender o que cada forma oferece e escolher consistentemente dentro de um projeto.
function UserCard({ name, email }: { name: string; email: string }) {
return (
<div>
<h2>{name}</h2>
<p>{email}</p>
</div>
);
}UserCard acima da linha onde ela é definidaUserCard pelo nomethis - irrelevante para componentes, mas significa que pode ser usada com .bind() se necessárioconst UserCard = ({ name, email }: { name: string; email: string }) => {
return (
<div>
<h2>{name}</h2>
<p>{email}</p>
</div>
);
};this léxico - herda this do escopo circundante (irrelevante para componentes de função, mas importa em callbacks de componentes de classe)constconst para tudoconst UserCard = ({ name, email }: { name: string; email: string }) => (
<div>
<h2>{name}</h2>
<p>{email}</p>
</div>
);return - o corpo inteiro é uma única expressãoexport default function Page() {
return <main>Home</main>;
}page.tsx, layout.tsx, loading.tsx, error.tsxPage, não Anonymousconst Page = () => {
return <main>Home</main>;
};
export default Page;// Anexando propriedades estáticas
const Tabs = ({ children }: { children: React.ReactNode }) => {
return <div>{children}</div>;
};
Tabs.Panel = TabPanel;
Tabs.List = TabList;
export default Tabs;export function UserCard({ name }: { name: string }) {
return <h2>{name}</h2>;
}import { UserCard } from "./user-card"// components/status.tsx - múltiplos componentes relacionados
export function StatusBadge({ status }: { status: string }) {
return <span className="badge">{status}</span>;
}
export function StatusIcon({ status }: { status: string }) {
return <span className="icon">{status === "active" ? "🟢" : "🔴"}</span>;
}export const UserCard = ({ name }: { name: string }) => (
<h2>{name}</h2>
);export default function ({ name }: { name: string }) {
return <h2>{name}</h2>;
}Anonymous ou _defaultReact.FC / React.FunctionComponent (Legado)const UserCard: React.FC<{ name: string }> = ({ name }) => {
return <h2>{name}</h2>;
};children em tipos React mais antigos (pré-React 18)children implícitos de React.FC - agora equivalente à tipagem simples| Forma | Içada (Hoisted) | Nomeada no DevTools | Tree-Shakeable | Melhor Para |
|---|---|---|---|---|
function Name() {} | Sim | Sim | Apenas se exportada | Uso geral, páginas Next.js |
const Name = () => {} | Não | Sim (inferido) | Apenas se exportada | Equipes que preferem const |
const Name = () => () | Não | Sim (inferido) | Apenas se exportada | Componentes minúsculos, apenas JSX |
export default function Name() | Sim | Sim | Não (padrão) | Páginas/layouts Next.js |
export function Name() | Sim | Sim | Sim | Componentes compartilhados, utilitários |
export const Name = () => {} | Não | Sim (inferido) | Sim | Estilo const consistente |
React.FC<Props> | Não | Sim (inferido) | Apenas se exportada | Apenas código legado |
Não há diferença funcional entre function e arrow para componentes. React não se importa. Escolha com base nas convenções da sua equipe:
Padrões recomendados:
// Páginas, layouts, rotas Next.js → export padrão + declaração de função
export default function DashboardPage() { ... }
// Componentes compartilhados → export nomeado + declaração de função
export function UserCard({ name }: UserCardProps) { ... }
// Utilitários internos no mesmo arquivo → declaração de função simples
function formatStatus(status: string) { ... }Se sua equipe usa funções arrow:
// Páginas Next.js → ainda use declaração de função para legibilidade
export default function DashboardPage() { ... }
// Todo o resto → arrow
export const UserCard = ({ name }: UserCardProps) => { ... };
const formatStatus = (status: string) => { ... };Declarações de função são içadas - elas estão disponíveis antes de sua posição textual no arquivo. Funções arrow atribuídas a const não são.
// Isso funciona - a declaração de função é içada
export default function Page() {
return <Sidebar />;
}
function Sidebar() {
return <nav>Links</nav>;
}// Isso falha - const NÃO é içada
export default function Page() {
return <Sidebar />; // ReferenceError: Cannot access 'Sidebar' before initialization
}
const Sidebar = () => <nav>Links</nav>;Na prática, isso raramente importa porque a maioria dos componentes está em arquivos separados. Importa quando você tem componentes auxiliares abaixo do export principal no mesmo arquivo.
Declarações de função e funções arrow lidam com genéricos de forma diferente em TSX:
// Declaração de função - sintaxe limpa
function List<T>({ items, render }: { items: T[]; render: (item: T) => React.ReactNode }) {
return <ul>{items.map((item, i) => <li key={i}>{render(item)}</li>)}</ul>;
}
// Função Arrow - precisa de vírgula final para desambiguar de JSX
const List = <T,>({ items, render }: { items: T[]; render: (item: T) => React.ReactNode }) => {
return <ul>{items.map((item, i) => <li key={i}>{render(item)}</li>)}</ul>;
};O <T,> com vírgula final é necessário porque <T> em um arquivo .tsx é analisado como uma tag JSX. A vírgula diz ao TypeScript que é um genérico. Este é um caso onde declarações de função têm uma clara vantagem sintática.
displayName para DepuraçãoComponentes de ordem superior (HOCs) e React.memo podem perder o nome do componente. Defina displayName explicitamente:
const UserCard = React.memo(({ name }: { name: string }) => (
<h2>{name}</h2>
));
UserCard.displayName = "UserCard";
// Com uma declaração de função, o nome é preservado automaticamente
const UserCard = React.memo(function UserCard({ name }: { name: string }) {
return <h2>{name}</h2>;
});
// displayName é automaticamente "UserCard" - nenhuma atribuição manual necessáriaforwardRef// Expressão de função dentro de forwardRef
const Input = React.forwardRef<HTMLInputElement, InputProps>(
function Input({ label, ...props }, ref) {
return (
<label>
{label}
<input ref={ref} {...props} />
</label>
);
}
);
// Função Arrow dentro de forwardRef
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ label, ...props }, ref) => (
<label>
{label}
<input ref={ref} {...props} />
</label>
)
);
// React 19: ref é uma prop regular - forwardRef não é necessário
function Input({ label, ref, ...props }: InputProps & { ref?: React.Ref<HTMLInputElement> }) {
return (
<label>
{label}
<input ref={ref} {...props} />
</label>
);
}Componentes de Servidor podem ser async - uma sintaxe que só funciona com declarações de função e funções arrow com corpos de bloco:
// Declaração de função - limpa
export default async function PostsPage() {
const posts = await getPosts();
return <ul>{posts.map(p => <li key={p.id}>{p.title}</li>)}</ul>;
}
// Função Arrow - também funciona
const PostsPage = async () => {
const posts = await getPosts();
return <ul>{posts.map(p => <li key={p.id}>{p.title}</li>)}</ul>;
};
export default PostsPage;Retorno implícito (=> (...)) não pode ser async porque await é uma declaração, não uma expressão.
Exports padrão anônimos perdem o nome no DevTools e traces de pilha. export default function() {} aparece como Anonymous. Sempre nomeie a função, mesmo em exports padrão.
Funções Arrow precisam de <T,> para genéricos em arquivos .tsx. Sem a vírgula final, <T> é analisado como um elemento JSX. Declarações de função não têm essa ambiguidade.
Componentes const não são içados. Se você definir componentes auxiliares abaixo do export principal no mesmo arquivo, use declarações de função ou mova os auxiliares para cima do componente principal.
React.FC implicitamente incluía children antes do React 18. Se você estiver migrando do React 17, remover React.FC pode expor erros de tipo onde children foi usado, mas não explicitamente tipado.
Retorno implícito quebra quando você adiciona lógica. const Card = () => (<div>...</div>) deve ser reescrito para const Card = () => { const x = ...; return <div>...</div>; } quando você adiciona qualquer declaração antes do JSX.
export default combinado com const é um processo de duas etapas. Você não pode escrever export default const Name = ... - é um erro de sintaxe. Use export default function Name() ou declare a const primeiro, depois export default Name.
Regras do ESLint podem conflitar. react/function-component-definition impõe um estilo. prefer-arrow-callback pode conflitar. Alinhe sua configuração do ESLint com a convenção escolhida pela sua equipe para evitar mudanças constantes.
Misturar estilos em um arquivo confunde contribuidores. Se UserCard for uma declaração de função e Avatar logo abaixo for uma função arrow, os leitores perdem tempo se perguntando se a diferença é intencional. Seja consistente dentro de um arquivo.
| Alternativa | Usar Quando |
|---|---|
| Componentes de Classe | Bases de código legadas, error boundaries (até React 19 useErrorBoundary) |
Componentes de Servidor (async function) | Busca de dados em tempo de renderização sem JS no cliente |
| Componentes de Ordem Superior (HOC) | Preocupações transversais (autenticação, logging) - menos comum agora com hooks |
| Render Props | Composição dinâmica de comportamento - em grande parte substituído por hooks |
Revisado por Chris St. John·Última atualização: 10 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥