React tem um modelo poderoso de composição, e recomedamos usar composição ao invés de herança para reusar código entre componentes.
Nesta seção, vamos considerar vários problemas que novos desenvolvedores em react geralmente resolvem com herança, e mostramos como podemos resolver com composição.
Alguns componentes não conhecem seus filhos antes do tempo. Isto é especialmente comum para componentes como Sidebar
ou Dialog
que representam "caixas" genéricas.
Recomendamos que esses componentes usem a propriedade especial children
para passar elementos filhos diretamente para sua saída:
function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children}
</div>
);
}
Isso permite que outros componentes passem filhos arbitrários para eles com JSX aninhado:
function WelcomeDialog() {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
Welcome
</h1>
<p className="Dialog-message">
Thank you for visiting our spacecraft!
</p>
</FancyBorder>
);
}
Qualquer coisa dentro da tag <FancyBorder>
é passado para dentro do componente FancyBorder
como uma propriedade children
. Uma vez que FancyBorder
renderiza {props.children}
dentro de uma <div>
, os elementos passados aparecem na saída final.
Enquanto isso é menos comum, às vezes você pode precisar de múltiplos "buracos" em um componente. nesses casos você pode vir usar suas própria convenção ao invés de usar children
:
function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left}
</div>
<div className="SplitPane-right">
{props.right}
</div>
</div>
);
}
function App() {
return (
<SplitPane
left={
<Contacts />
}
right={
<Chat />
} />
);
}
Elementos React como <Contacts />
e <Chat />
são apenas objetos, então você pode passá-los como propriedades como qualquer outro dado.
As vezes pensamos em componentes como sendo "casos especiais" de outros componentes. Por exemplo, nós podemos dizer que um WelcomeDialog
é um caso especial de Dialog
.
Em React, isto também é alcançado pela composição, onde um componente mais "específico" renderiza um mais "genérico" e configura-o com as propriedades:
function Dialog(props) {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
{props.title}
</h1>
<p className="Dialog-message">
{props.message}
</p>
</FancyBorder>
);
}
function WelcomeDialog() {
return (
<Dialog
title="Welcome"
message="Thank you for visiting our spacecraft!" />
);
}
Composição funciona igualmente bem para componentes definidos como classes:
function Dialog(props) {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
{props.title}
</h1>
<p className="Dialog-message">
{props.message}
</p>
{props.children}
</FancyBorder>
);
}
class SignUpDialog extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleSignUp = this.handleSignUp.bind(this);
this.state = {login: ''};
}
render() {
return (
<Dialog title="Mars Exploration Program"
message="How should we refer to you?">
<input value={this.state.login}
onChange={this.handleChange} />
<button onClick={this.handleSignUp}>
Sign Me Up!
</button>
</Dialog>
);
}
handleChange(e) {
this.setState({login: e.target.value});
}
handleSignUp() {
alert(`Welcome aboard, ${this.state.login}!`);
}
}
No Facebook, usamos React em milhares de componentes e não encontramos nenhum caso de uso onde recomendamos a criação de componentes com hierarquias de herança.
Propriedades e composição nos dão toda a flexibilidade que precisamos para customizar o visual e o comportamento de um componente de forma explícita e segura. Lembre-se que componentes podem aceitar propriedades arbitrárias, incluindo valores primitivos, elementos React ou funções.
Se você quer reusar funcionalidades não visíveis entre componentes, nós sugerimos extrai-lá para um módulo JavaScript separado. Os componentes podem importá-lo e usar essa função, objeto ou classe, sem extendê-lo.