O autor selecionou a Creative Commons para receber uma doação como parte do programa Write for DOnations.
Neste tutorial, você criará componentes de encapsulamento com props usando a biblioteca React JavaScript. Componentes de encapsulamento são componentes que encapsulam componentes desconhecidos e fornecem uma estrutura padrão para exibir os componentes filhos. Este padrão é útil para criar elementos de interface de usuário (UI) que são usados repetidamente ao longo de um projeto, como modais, páginas de modelo e contos informacionais.
Para criar componentes de encapsulamento, você primeiro aprenderá a usar os operadores rest e spread para coletar as props não utilizadas para passar aos componentes aninhados. Em seguida, você criará um componente que utiliza o componente embutido children
para envolver componentes aninhados no JSX como se eles fossem elementos HTML. Por fim, você passará componentes como props para criar encapsuladores flexíveis que podem incorporar JSX personalizados em várias localizações em um componente.
Durante o tutorial, você compilará componentes para exibir uma lista de dados de animais na forma de cartões. Você aprenderá a dividir dados e refatorar componentes à medida que você cria componentes de encapsulamento flexíveis. Ao final deste tutorial, você terá uma aplicação funcional que usará técnicas avançadas de prop para criar componentes reutilizáveis que irão escalar e se adaptar à medida que sua aplicação cresce e se modifica.
Nota: o primeiro passo define um projeto em branco no qual você desenvolverá o exercício do tutorial. Se você já tiver um projeto de trabalho e deseja ir diretamente ao trabalho com os props, vá para o Passo 2.
Você precisará de um ambiente de desenvolvimento executando o Node.js; este tutorial foi testado na versão 10.20.1 do Node.js e na versão 6.14.4 do npm. Para instalar essa versão em macOS ou Ubuntu 18.04, siga os passos descritos no artigo sobre Como instalar o Node.js e criar um ambiente de desenvolvimento local em macOS ou a seção intitulada Instalando e usando um PPA, do artigo sobre Como instalar o Node.js no Ubuntu 18.04.
Neste tutorial, você criará um app com o Create React App. Você pode encontrar instruções para instalar uma aplicação com o Create React App e informações gerais sobre como ele funciona no tutorial How To Set Up a React Project with Create React App.
Você estará usando componentes React, sobre os quais você pode aprender em nosso tutorial How To Create Custom Components in React. Isso também ajudará a ter uma compreensão básica das props do React, que você pode aprender em How to Customize React Components with Props.
Você também precisará de um conhecimento básico de JavaScript, que você pode encontrar em nossa série How To Code in JavaScript, juntamente com um conhecimento básico de HTML e de CSS. Um boa fonte de recursos para HTML e CSS é a Rede do desenvolvedor Mozilla.
Neste passo, você criará um novo projeto utilizando o Create React App. Em seguida, você excluirá o projeto de exemplo e os arquivos relacionados que foram instalados durante a inicialização dele. Por fim, você criará uma estrutura de arquivos simples para organizar seus componentes. Isso lhe dará uma base sólida sobre a qual construir a aplicação de encapsulamento deste tutorial no próximo passo.
Para começar, crie um novo projeto. Em sua linha de comando, execute o script a seguir para instalar um novo projeto usando o create-react-app
:
- npx create-react-app wrapper-tutorial
Após o projeto ser finalizado, vá para o diretório:
- cd wrapper-tutorial
Em uma nova guia ou janela do terminal, inicie o projeto usando o script start do Create React App. O navegador irá atualizar-se automaticamente nas alterações, então deixe este script em execução enquanto você trabalha:
- npm start
Você receberá um servidor local em execução. Se o projeto não abriu na janela de um navegador, você pode abri-lo com http://localhost:3000/
. Se o estiver executando em um servidor remoto, o endereço será http://your_domain:3000
.
Seu navegador carregará com um aplicativo simples do React, que vem incluído como parte do Create React App:
Você irá desenvolver um conjunto completamente novo de componentes personalizados. Assim, será necessário começar removendo um pouco de código boilerplate para que você possa ter um projeto vazio.
Para iniciar, abra o src/App.js
em um editor de texto. Esse é o componente raiz que é injetado na página. Todos os componentes iniciarão a partir daqui. Saiba mais sobre o App.js
em Como configurar um projeto React com o Create React App.
Abra o src/App.js
com o seguinte comando:
- nano src/App.js
Você verá um arquivo como este:
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
Exclua a linha import logo from './logo.svg';
. Em seguida, substitua tudo na instrução return
para retornar um conjunto de tags vazias: <></>
. Isso lhe dará uma página válida que não retorna nada. O código final ficará parecido com este:
import React from 'react';
import './App.css';
function App() {
return <></>;
}
export default App;
Salve e saia do editor de texto.
Por fim, exclua o logo. Você não o usará neste seu aplicativo e é aconselhável remover arquivos não utilizados durante o trabalho. Isso evitará confusões futuras.
Na janela do terminal, digite o seguinte comando:
- rm src/logo.svg
Se você olhar em seu navegador, verá uma tela vazia.
Com o projeto de exemplo do Create React App limpo, crie uma estrutura de arquivos simples. Isso ajudará você a manter os componentes isolados e independentes.
Crie um diretório chamado components
no diretório src
. Isso irá conter todos os seus componentes personalizados.
- mkdir src/components
Cada componente terá o próprio diretório para armazenar o arquivo de componente com os estilos, imagens (se houver) e testes.
Crie um diretório para o App
:
- mkdir src/components/App
Mova todos os arquivos App
para esse diretório. Use o curinga *
para selecionar quaisquer arquivos que comecem com App.
, independentemente da extensão. Depois, utilize o comando mv
para colocá-los no novo diretório.
- mv src/App.* src/components/App
Em seguida, atualize o caminho de importação relativo em index.js
, que é o componente raiz que inicializa todo o processo.
- nano src/index.js
A instrução de importação precisa apontar para o arquivo Apps.js
no diretório App
. Portanto, faça a seguinte alteração destacada:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/App/App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
Salve e saia do arquivo.
Agora que o projeto está configurado, crie o primeiro componente.
...props
Neste passo, você criará um componente para exibir um conjunto de dados sobre um grupo de animais. Seu componente conterá um segundo componente aninhado para exibir algumas informações visualmente. Para conectar o componente pai e o componente aninhado, você vai utilizar os operadores rest e spread para repassar props não utilizadas do pai para o filho, sem que o pai precise estar ciente dos nomes ou tipos das props.
Ao final deste passo, você terá um componente pai que pode fornecer props aos componentes aninhados sem ter que saber quais são as props. Isso manterá o componente pai flexível, permitindo que você atualize o componente filho sem ter que alterar o pai.
AnimalCard
Para começar, crie um conjunto de dados para seus animais. Primeiro, abra um arquivo contendo o conjunto de dados no diretório components/App
.
- nano src/components/App/data.js
Adicione os seguintes dados:
export default [
{
name: 'Lion',
scientificName: 'Panthero leo',
size: 140,
diet: ['meat']
},
{
name: 'Gorilla',
scientificName: 'Gorilla beringei',
size: 205,
diet: ['plants', 'insects']
},
{
name: 'Zebra',
scientificName: 'Equus quagga',
size: 322,
diet: ['plants'],
}
]
Esta lista de animais é uma matriz de objetos que inclui o nome do animal, nome científico, peso e dieta.
Salve e feche o arquivo.
A seguir, crie um diretório para o componente AnimalCard
:
- mkdir src/components/AnimalCard
Abra um novo arquivo no diretório:
- nano src/components/AnimalCard/AnimalCard.js
Agora, adicione um componente que irá usar name
, diet
e size
como uma prop e exiba-o:
import React from 'react';
import PropTypes from 'prop-types';
export default function AnimalCard({ diet, name, size }) {
return(
<div>
<h3>{name}</h3>
<div>{size}kg</div>
<div>{diet.join(', ')}.</div>
</div>
)
}
AnimalCard.propTypes = {
diet: PropTypes.arrayOf(PropTypes.string).isRequired,
name: PropTypes.string.isRequired,
size: PropTypes.number.isRequired,
}
Aqui, você está desestruturando as props na lista de parâmetros para a função AnimalCard
, depois mostrando os dados em uma div
. Os dados de diet
são listados como uma única string usando o método join()
. Cada parte de dados inclui uma PropType
correspondente para garantir que o tipo de dados esteja correto.
Salve e feche o arquivo.
Agora que você tem seu componente e seus dados, você precisa combiná-los. Para fazer isso, importe o componente e os dados no componente raiz do seu projeto: App.js
.
Primeiro, abra o componente:
- nano src/components/App/App.js
A partir daí, você pode fazer um loop sobre os dados e retornar um novo AnimalCard
com as props relevantes. Adicione as linhas destacadas ao App.js
:
import React from 'react';
import './App.css';
import animals from './data';
import AnimalCard from '../AnimalCard/AnimalCard';
function App() {
return (
<div className="wrapper">
{animals.map(animal =>
<AnimalCard
diet={animal.diet}
key={animal.name}
name={animal.name}
size={animal.size}
/>
)}
</div>
);
}
export default App;
Salve e feche o arquivo.
À medida que você trabalha em projetos mais complexos, seus dados virão de lugares mais variados, como APIs, localStorage
, ou arquivos estáticos. Mas o processo para usar cada um deles será semelhante: atribuir os dados a uma variável e fazer um loop sobre os dados. Neste caso, o dado é de um arquivo estático, então você está importando diretamente para uma variável.
Neste código, você utiliza o método .map()
para iterar sobre animals
e exibir as props. Observe que você não precisa usar cada parte de dados. Você não está passando explicitamente a propriedade scientificName
, por exemplo. Você também está adicionando uma prop.key
separada que o React usará para acompanhar os dados mapeados. Finalmente, você está encapsulando o código com uma div
com um className
wrapper
que você usará para adicionar algum estilo.
Para adicionar este estilo, abra o App.css
:
- nano src/components/App/App.css
Remova o estilo padrão e adicione propriedades flex a uma classe chamada wrapper
:
.wrapper {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
padding: 20px;
}
Isso usará o layout flexbox para organizar os dados para que eles se alinhem. padding
dá algum espaço na janela do navegador, e justify-content
espalha o espaço extra entre os elementos.
Salve e saia do arquivo. Quando fizer isso, o navegador será recarregado e você verá alguns dados espaçados.
Você tem agora um componente simples que mostra os dados. Mas digamos que você queira dar um pouco de charme aos dados de diet
convertendo o texto em um emoji. Você pode fazer isso convertendo os dados em seu componente.
O React foi projetado para ser flexível, então, quando você estiver pensando em como converter dados, terá algumas opções diferentes:
Cada abordagem é boa quando aplicada ao caso de uso correto, e você se encontrará alternando entre elas enquanto você constrói uma aplicação. Para evitar a abstração prematura e complexidade, você deve usar a primeira opção para começar. Se você desejar reutilizar a lógica, poderá extrair a função separadamente do componente. A terceira opção é melhor se você quiser ter uma peça reutilizável que inclua a lógica e o markup, ou se você quiser isolar para usar em toda a aplicação.
Neste caso, vamos criar um novo componente, uma vez que vamos querer adicionar mais dados posteriormente e estamos combinando o markup com a lógica de conversão.
O novo componente será chamado AnimalDetails
. Para fazer isso, crie um novo diretório:
- mkdir src/components/AnimalDetails
Em seguida, abra AnimalDetails.js
em seu editor de texto:
- nano src/components/AnimalDetails/AnimalDetails.js
Dentro do arquivo, faça um pequeno componente que exibe diet
como um emoji:
import React from 'react';
import PropTypes from 'prop-types';
import './AnimalDetails.css';
function convertFood(food) {
switch(food) {
case 'insects':
return '🐜';
case 'meat':
return '🍖';
case 'plants':
default:
return '🌱';
}
}
export default function AnimalDetails({ diet }) {
return(
<div className="details">
<h4>Details:</h4>
<div>
Diet: {diet.map(food => convertFood(food)).join(' ')}
</div>
</div>
)
}
AnimalDetails.propTypes = {
diet: PropTypes.arrayOf(PropTypes.string).isRequired,
}
O objeto AnimalDetails.propTypes
define a função para fazer uma prop de diet
que é uma matriz de strings. Em seguida, dentro do componente, o código faz um loop sobre diet
e converte a string em um emoji usando a instrução switch.
Salve e feche o arquivo.
Você também está importando o CSS. Desse modo, vamos adicionar isso agora.
Abra AnimalDetails.css
:
- nano src/components/AnimalDetails/AnimalDetails.css
Adicione algum CSS para dar ao elemento uma borda e uma margem para separar os detalhes do restante do componente:
.details {
border-top: gray solid 1px;
margin: 20px 0;
}
Usamos .details
para fazer a correspondência entre a regra e os elementos com uma className
details
.
Salve e feche o arquivo.
Agora que você tem um novo componente personalizado, você pode adicioná-lo ao seu componente AnimalCard
. Abra AnimalCard.js
:
- nano src/components/AnimalCard/AnimalCard.js
Substitua a instrução diet.join
pelo novo componente AnimalDetails
e passe diet
como uma prop adicionando as linhas destacadas:
import React from 'react';
import PropTypes from 'prop-types';
import AnimalDetails from '../AnimalDetails/AnimalDetails';
export default function AnimalCard({ diet, name, size }) {
return(
<div>
<h3>{name}</h3>
<div>{size}kg</div>
<AnimalDetails
diet={diet}
/>
</div>
)
}
AnimalCard.propTypes = {
diet: PropTypes.arrayOf(PropTypes.string).isRequired,
name: PropTypes.string.isRequired,
size: PropTypes.number.isRequired,
}
Salve o arquivo e você verá os novos detalhes no navegador.
...props
Os componentes estão funcionando bem juntos, mas há uma ligeira ineficiência em AnimalCard
. Você está explicitamente extraindo diet
do argumento props
, mas você não está usando os dados. Em vez disso, você está passando-os através do componente. Não há nada inerentemente errado nisso — de fato, geralmente é melhor errar ao lado de muita comunicação. Mas ao fazer isso, você torna seu código mais difícil de manter. Sempre que você quiser passar novos dados para AnimalDetails
, você precisa atualizar três lugares: App
, onde você passa as props, AnimalDetails
, que consome a prop, e AnimalCard
, que é o intermediário.
Uma maneira melhor é reunir quaisquer objetos não utilizados dentro de AnimalCard
e, em seguida, passá-los diretamente para AnimalDetails
. Isso dá a você a chance de fazer alterações em AnimalDetails
sem alterar AnimalCard
. De fato, AnimalCard
não precisa saber nada sobre as props ou sobre PropTypes
que estão entrando em AnimalDetails
.
Para fazer isso, você usará o operador rest do objeto. Este operador coleta quaisquer itens que não sejam extraídos durante a desestruturação e os salva em um novo objeto.
Aqui está um exemplo simples:
const dog = {
name: 'dog',
diet: ['meat']
}
const { name, ...props } = dog;
Neste caso, a variável name
será 'dog'
e as props
da variável serão { diet: ['meat']}
.
Até agora, você passou todas as props como se elas fossem atributos HTML, mas você também pode usar objetos para enviar props. Para usar um objeto como uma prop, você precisa usar o operador de espalhamento (spread) —...props
— entre chaves. Isso mudará cada par de chave-valor em uma prop.
Abra AnimalCard.js
:
- nano src/components/AnimalCard/AnimalCard.js
Lá dentro, remova diet
do objeto desestruturado e, em vez disso, colete o resto das props em uma variável chamada props
. Em seguida, passe esses props diretamente para AnimalDetails
:
import React from 'react';
import PropTypes from 'prop-types';
import AnimalDetails from '../AnimalDetails/AnimalDetails';
export default function AnimalCard({ name, size, ...props }) {
return(
<div>
<h3>{name}</h3>
<div>{size}kg</div>
<AnimalDetails
{...props}
/>
</div>
)
}
AnimalCard.propTypes = {
name: PropTypes.string.isRequired,
size: PropTypes.number.isRequired,
}
Observe que você pode remover o PropType
diet
, uma vez que você não está usando a prop neste componente.
Neste caso, você está apenas passando uma prop para AnimalDetails
. Em casos onde você tem várias props, a ordem fará diferença. Uma prop posterior substituirá as props anteriores; portanto, se você tiver uma prop que queira ter prioridade, verifique se ela é a última. Isso pode causar alguma confusão se seu objeto props
tiver uma propriedade que também seja um valor nomeado.
Salve e feche o arquivo. O navegador irá atualizar e tudo ficará igual:
Para ver como o objeto ...props
adiciona flexibilidade, vamos passar scientificName
para AnimalDetails
através do componente AnimalCard
.
Primeiro, abra o App.js
:
- nano src/components/App/App.js
Em seguida, passe scientificName
como uma prop:
import React from 'react';
import './App.css';
import animals from './data';
import AnimalCard from '../AnimalCard/AnimalCard';
function App() {
return (
<div className="wrapper">
{animals.map(animal =>
<AnimalCard
diet={animal.diet}
key={animal.name}
name={animal.name}
size={animal.size}
scientificName={animal.scientificName}
/>
)}
</div>
);
}
export default App;
Salve e feche o arquivo.
Pule AnimalCard
; você não precisará fazer nenhuma alteração lá. Em seguida, abra AnimalDetails
para que você possa consumir a nova prop:
- nano src/components/AnimalDetails/AnimalDetails.js
A nova prop será uma string, que você adicionará à lista details
junto com uma linha declarando o PropType
:
import React from 'react';
...
export default function AnimalDetails({ diet, scientificName }) {
return(
<div className="details">
<h4>Details:</h4>
<div>
Scientific Name: {scientificName}.
</div>
<div>
Diet: {diet.map(food => convertFood(food)).join(' ')}
</div>
</div>
)
}
AnimalDetails.propTypes = {
diet: PropTypes.arrayOf(PropTypes.string).isRequired,
scientificName: PropTypes.string.isRequired,
}
Salve e feche o arquivo. Quando fizer isso, o navegador irá atualizar e você verá os novos detalhes sem quaisquer alterações no componente AnimalCard
:
Neste passo, você aprendeu como criar props pais flexíveis que podem pegar props desconhecidas e passá-las em componentes aninhados com o operador de espalhamento. Este é um padrão comum que lhe dará a flexibilidade que você precisa para criar componentes com responsabilidades focadas. No próximo passo, você criará componentes que podem pegar componentes desconhecidos como uma prop usando a prop embutida children
.
children
Neste passo, você criará um componente de encapsulamento que pode pegar um grupo desconhecido de componentes como uma prop. Isso lhe dará a capacidade de aninhar componentes como HTML padrão, e isto lhe dará um padrão para criar encapsulamentos reutilizáveis, permitindo que você crie uma variedade de componentes que precisam de um projeto comum, porém com um interior flexível.
O React lhe fornece uma prop embutida chamado children
que coleta quaisquer componentes children. Usar isso torna a criação de componentes de encapsulamento intuitiva e legível.
Para começar, crie um novo componente chamado Card
. Este será um componente de encapsulamento para criar um estilo padrão para qualquer novo componente card.
Crie um novo diretório:
- mkdir src/components/Card
Em seguida, abra o componente Card
em seu editor de texto:
- nano src/components/Card/Card.js
Crie um componente que pegue children
e title
como props e os encapsule em uma div
adicionando o seguinte código:
import React from 'react';
import PropTypes from 'prop-types';
import './Card.css';
export default function Card({ children, title }) {
return(
<div className="card">
<div className="card-details">
<h2>{title}</h2>
</div>
{children}
</div>
)
}
Card.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.element),
PropTypes.element.isRequired
]),
title: PropTypes.string.isRequired,
}
Os PropTypes
para children
são novos. A prop children
pode ser tanto um elemento JSX como uma matriz de elementos JSX. title
é uma string.
Salve e feche o arquivo.
Em seguida, adicione algum estilo. Abra o Card.css
:
- nano src/components/Card/Card.css
Seu cartão terá uma borda e uma linha embaixo dos detalhes.
.card {
border: black solid 1px;
margin: 10px;
padding: 10px;
width: 200px;
}
.card-details {
border-bottom: gray solid 1px;
margin-bottom: 20px;
}
Salve e feche o arquivo. Agora que você tem seu componente você precisa usá-lo. Você pode encapsular cada AnimalCard
com o componente Card
no App.js
, mas como o nome AnimalCard
implica que ele já seja um Card
, seria melhor usar o componente Card
dentro de AnimalCard
.
Abra AnimalCard
:
- nano src/components/AnimalCard/AnimalCard.js
Diferentemente de outras props, você não passa children
explicitamente. Em vez disso, você inclui o JSX como se eles fossem elementos HTML filhos. Em outras palavras, você apenas os aninha dentro do elemento, como a seguir:
import React from 'react';
import PropTypes from 'prop-types';
import Card from '../Card/Card';
import AnimalDetails from '../AnimalDetails/AnimalDetails';
export default function AnimalCard({ name, size, ...props }) {
return(
<Card title="Animal">
<h3>{name}</h3>
<div>{size}kg</div>
<AnimalDetails
{...props}
/>
</Card>
)
}
AnimalCard.propTypes = {
name: PropTypes.string.isRequired,
size: PropTypes.number.isRequired,
}
Diferentemente de um componente React, você não precisa ter um único elemento raiz como um filho. É por isso que o PropType
para Card
especificou que ele poderia ser uma matriz de elementos ou um único elemento. Além de passar children
como componentes aninhados, você está dando ao cartão um título Animal
.
Salve e feche o arquivo. Quando você fizer isso, o navegador irá atualizar e você verá o componente do cartão atualizado.
Agora, você tem um componente Card
reutilizável que pode pegar qualquer número de children aninhados. A principal vantagem disso é que você pode reutilizar o Card
com qualquer componente arbitrário. Se você quisesse criar um cartão Plant
, você poderia fazer isso encapsulando as informações de plant com o componente Card
. Ele nem mesmo precisa se relacionar: se você quisesse reutilizar o componente Card
em uma aplicação completamente diferente que enumera coisas como música ou dados de conta, você também poderia fazer isso. O componente Card
não liga para o que os children são; você está apenas reutilizando o elemento de encapsulamento, que neste caso é a borda estilizada e o título.
A desvantagem de usar children
é que você pode ter apenas uma instância da prop child. Ocasionalmente, você desejará que um componente tenha JSX personalizado em vários locais Felizmente, você pode fazer isso passando componentes JSX e React como props, que abordaremos no próximo passo.
Neste passo, você modificará seu componente Card
para pegar outros componentes como props. Isso dará ao seu componente flexibilidade máxima para exibir componentes desconhecidos ou JSX em vários locais da página. Diferentemente de children
, que você só pode usar uma única vez, você pode ter tantos componentes quanto props, dando ao seu componente de encapsulamento a capacidade de se adaptar a uma variedade de necessidades, mantendo uma aparência e uma estrutura padrão.
Ao final deste passo, você terá um componente que pode encapsular componentes children e exibir outros componentes no cartão. Este padrão lhe dará flexibilidade quando você precisar criar componentes que precisam de informações mais complexas do que strings simples e números inteiros.
Vamos modificar o componente Card
para pegar um elemento React arbitrário chamado details
.
Primeiro, abra o componente Card
:
- nano src/components/Card/Card.js
Em seguida, adicione uma nova prop chamada details
e a coloque abaixo do elemento <h2>
:
import React from 'react';
import PropTypes from 'prop-types';
import './Card.css';
export default function Card({ children, details, title }) {
return(
<div className="card">
<div className="card-details">
<h2>{title}</h2>
{details}
</div>
{children}
</div>
)
}
Card.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.element),
PropTypes.element.isRequired
]),
details: PropTypes.element,
title: PropTypes.string.isRequired,
}
Card.defaultProps = {
details: null,
}
Esta prop terá o mesmo tipo de children
, mas ela deve ser opcional. Para torná-la opcional, você adiciona um valor padrão de null
. Neste caso, se um usuário não passar detalhes, o componente ainda será válido e não exibirá nada a mais.
Salve e feche o arquivo. A página irá atualizar e você verá a mesma imagem como antes:
Agora, adicione alguns detalhes ao AnimalCard
. Primeiro, abra AnimalCard
.
- nano src/components/AnimalCard/AnimalCard.js
Como o componente Card
já está usando children
, você precisará passar o novo componente JSX como uma prop. Como esses são todos mamíferos, adicione isso ao cartão, mas encapsule-o em tags <em>
para torná-lo itálico.
import React from 'react';
...
export default function AnimalCard({ name, size, ...props }) {
return(
<Card title="Animal" details={<em>Mammal</em>}>
<h3>{name}</h3>
<div>{size}kg</div>
<AnimalDetails
{...props}
/>
</Card>
)
}
...
Salve o arquivo. Quando você fizer isso, o navegador irá atualizar e você verá a atualização, incluindo a palavra Mammal.
Esta prop já é poderosa, pois ela pode pegar JSX de qualquer tamanho. Neste exemplo, você adicionou apenas um único elemento, mas você poderia passar o tanto de JSX quanto você queira. E também não precisa ser JSX. Se você tivesse um markup complicado por exemplo, você não iria querer passá-lo diretamente na prop; isso seria difícil de ler. Em vez disso, você poderia criar um componente separado e, em seguida, passar o componente como uma prop.
Para ver isto funcionando, passe AnimalDetails
para a prop details
:
import React from 'react';
...
export default function AnimalCard({ name, size, ...props }) {
return(
<Card
title="Animal"
details={
<AnimalDetails
{...props}
/>
}
>
<h3>{name}</h3>
<div>{size}kg</div>
</Card>
)
}
...
AnimalDetails
é mais complicado e tem uma série de linhas de markup. Se você fosse adicioná-lo diretamente a details
, ele aumentaria a prop substancialmente e o tornaria difícil de ler.
Salve e feche o arquivo. Quando você fizer isso, o navegador irá atualizar e os detalhes irão aparecer no topo do cartão.
Agora, você tem um componente Card
que pode pegar JSX personalizado e colocá-lo em vários pontos. Você não está restrito a uma única prop; você pode passar elementos para quantas props desejar. Isso lhe dá a capacidade de criar componentes de encapsulamento flexíveis que podem dar a outros desenvolvedores a oportunidade de personalizar um componente, mantendo seu estilo e funcionalidade gerais.
Passar um componente como uma prop não é perfeito. É um pouco mais difícil de ler e não é tão claro quanto passar children
, mas eles são tão flexíveis e você pode usar quantos deles desejar em um componente. Você deve usar children
primeiro, mas não hesite em voltar para props, caso isso não seja o suficiente.
Neste passo, você aprendeu como passar componentes JSX e React como props para outro componente. Isso dará ao seu componente a flexibilidade para lidar com muitas situações onde um componente de encapsulamento pode precisar de várias props para lidar com JSX ou com componentes.
Você criou uma variedade de componentes de encapsulamento que podem exibir dados de maneira flexível, mantendo uma aparência e uma estrutura previsíveis. Você criou componentes que podem coletar e passar props desconhecidas para componentes aninhados. Você também usou a prop embutido children
para criar componentes de encapsulamento que podem lidar com um número arbitrário de elementos aninhados. Por fim, você criou um componente que pode pegar componentes JSX ou React como uma prop para que seu componente de encapsulamento possa lidar com várias instâncias diferentes de personalizações.
Componentes de encapsulamento lhe fornecem a capacidade de se adaptar a circunstâncias desconhecidas, ao mesmo tempo em que maximiza a reutilização de código e a consistência. Este padrão é útil para criar elementos de UI básicos que você reutilizará ao longo de uma aplicação, incluindo: botões, alertas, modais, slide shows, e muito mais. Você se verá voltando a ele muitas vezes.
Se você quiser analisar mais tutoriais de React, dê uma olhada em nossa página sobre o React ou retorne à página da série Como Programar em React.js.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Brooo, sensacional o artigo, me ajudo bastante a aprender o que é wrapper e como criar ^^