Passando Props a um Componente
Componentes do React usam props para se comunicar um com ou outro. Todo componente pai pode passar alguma informação aos seus filhos por meio das props. Props podem te lembrar de atributos HTML, mas você pode passar qualquer valor JavaScript por meio delas, incluindo objetos, arrays, e funções.
Você aprenderá
- Como passar props para um componente
- Como ler props de um componente
- Como especificar valores padrão para as props
- Como passar JSX a um componente
- Como as props mudam com o tempo
Props familiares
Props são as informações que você passa usando uma tag JSX. Por exemplo, className
, src
, alt
, width
, e height
são algumas das props que você pode passar a uma <img>
:
function Avatar() { return ( <img className="avatar" src="https://i.imgur.com/1bX5QH6.jpg" alt="Lin Lanying" width={100} height={100} /> ); } export default function Profile() { return ( <Avatar /> ); }
As props que você pode passar a uma tag <img>
são predefinidas (A ReactDOM conforma-se ao padrão HTML). Mas você pode passar quaisquer props aos seus próprios componentes, como um <Avatar>
, para customizá-los. Veja como fazer isso!
Passando props para um componente
Neste código, o componente Profile
não está passando nenhuma prop ao seu componente filho, Avatar
:
export default function Profile() {
return (
<Avatar />
);
}
Você pode atribuir algumas props ao Avatar
em dois passos.
Passo 1: Passe props ao componente filho
Primeiro, passe algumas props ao Avatar
. Por exemplo, vamos passar duas props: person
(um objeto), e size
(um número):
export default function Profile() {
return (
<Avatar
person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }}
size={100}
/>
);
}
Agora você pode ler essas props dentro do componente Avatar
.
Passo 2: Leia props dentro de um componente filho
Você pode ler estas props listando seus nomes person, size
separados por vírgulas dentro de ({
e })
diretamente depois de function Avatar
. Isso permite que você as use dentro do código de Avatar
, assim como você faria com uma variável.
function Avatar({ person, size }) {
// person e size estão disponíveis aqui
}
Adicione alguma lógica a Avatar
que use as props person
e size
para a renderização, e pronto.
Agora você pode configurar Avatar
para que seja renderizado de várias maneiras diferentes usando props diferentes. Tente mudar os valores!
import { getImageUrl } from './utils.js'; function Avatar({ person, size }) { return ( <img className="avatar" src={getImageUrl(person)} alt={person.name} width={size} height={size} /> ); } export default function Profile() { return ( <div> <Avatar size={100} person={{ name: 'Katsuko Saruhashi', imageId: 'YfeOqp2' }} /> <Avatar size={80} person={{ name: 'Aklilu Lemma', imageId: 'OKS67lh' }} /> <Avatar size={50} person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }} /> </div> ); }
Props permitem que você pense sobre os componentes pai e filho independentemente. Por exemplo, você pode mudar as props person
ou size
dentro de Profile
sem ter que pensar sobre como Avatar
as usa. Similarmente, você é livre para mudar como Avatar
usa essas props, sem checar o Profile
.
Você pode pensar nas props como “controles” os quais você pode ajustar. Elas desempenham o mesmo papel que os argumentos para funções-de fato, props são o único argumento para o seu componente! Os componente funcionais do React aceitam apenas um argumento, um objeto props
:
function Avatar(props) {
let person = props.person;
let size = props.size;
// ...
}
Normalmente você não precisa de todo o objeto props
em si, então você pode desestruturá-lo em props individuais.
Especificando um valor padrão para uma prop
Se você quer dar a uma prop um valor padrão para usar quando nenhum valor for especificado, pode fazer isso com a desestruturação colocando =
e o valor padrão logo depois do parâmetro:
function Avatar({ person, size = 100 }) {
// ...
}
Agora, se <Avatar person={...} />
for renderizado sem a prop size
, size
será igual a 100
.
O valor padrão é apenas utilizado se a prop size
não for especificada ou se você passar size={undefined}
. Mas caso você passe size={null}
ou size={0}
, o valor padrão não será usado.
Encaminhando props com a sintaxe de espalhamento JSX
Às vezes, passar props se torna muito repetitivo:
function Profile({ person, size, isSepia, thickBorder }) {
return (
<div className="card">
<Avatar
person={person}
size={size}
isSepia={isSepia}
thickBorder={thickBorder}
/>
</div>
);
}
Não há nada de errado com código repetitivo-ele pode ser mais legível. Mas às vezes você pode valorizar concisão. Alguns componentes encaminham todas as suas props aos seus filhos, como Profile
faz com Avatar
. Como eles não usam nenhuma de suas props diretamente, pode fazer sentido usar uma sintaxe de espalhamento mais concisa:
function Profile(props) {
return (
<div className="card">
<Avatar {...props} />
</div>
);
}
Isso encaminha todas as props de Profile
ao Avatar
sem listar cada um de seus nomes.
Use a sintaxe de espalhamento com cuidado. Se você está a utilizando em quase todos os componentes, algo está errado. Muitas vezes, isso indica que você deveria dividir seus componentes e passar filhos como JSX. Mais sobre isso a seguir!
Passando JSX como children
É comum aninhar tags embutidas no navegador:
<div>
<img />
</div>
Às vezes você desejará aninhar seus próprios componentes da mesma forma:
<Card>
<Avatar />
</Card>
Quando você aninha conteúdo dentro de uma tag JSX, o componente pai irá receber esse conteúdo em uma prop chamada children
. Por exemplo, o componente Card
abaixo receberá a prop children
definida como <Avatar />
e o renderizará em uma wrapper div:
import Avatar from './Avatar.js'; function Card({ children }) { return ( <div className="card"> {children} </div> ); } export default function Profile() { return ( <Card> <Avatar size={100} person={{ name: 'Katsuko Saruhashi', imageId: 'YfeOqp2' }} /> </Card> ); }
Tente substituir o <Avatar>
dentro de <Card>
com algum texto para ver como o componente Card
pode encapsular conteúdo aninhado. Ele não precisa “saber” o que está sendo renderizado dentro dele. Você encontrará esse padrão flexível em muitos lugares.
É possível pensar sobre um componente com a prop children
como se ele tivesse um “buraco” o qual pode ser “preenchido” por seus componente pais com JSX arbitrária. Você frequentemente usará a prop children
para wrappers visuais: painéis, grids, etc.
Illustrated by Rachel Lee Nabors
Como props mudam com o passar do tempo
O componente Clock
abaixo recebe duas props de seu componente pai: color
e time
. (O código deste componente pai está omitido porque usa state, conceito o qual nós não vamos nos aprofundar ainda.)
Tente mudar a cor na caixa de seleção abaixo:
export default function Clock({ color, time }) { return ( <h1 style={{ color: color }}> {time} </h1> ); }
Este exemplo ilustra que um componente pode receber props diferentes com o passar o tempo. Props não são sempre estáticas! Aqui, a prop time
muda a cada segundo, e a prop color
muda quando você seleciona outra cor. As props refletem os dados de um componente a qualquer instante, não apenas num primeiro momento.
Entretanto, as props são imutáveis-um termo da ciência da computação o qual significa “inalterável”. Quando um componente precisa mudar suas props (por exemplo, em resposta à interação do usuário ou a novos dados), ele terá que “pedir” ao componente pai que passe props diferentes- um novo objeto! Suas props antigas serão então deixadas de lado, e eventualmente o motor do JavaScript irá recuperar a memória ocupada por elas.
Não tente “alterar props”. Quando você precisa responder a interações do usuário (como trocar a cor selecionada), você terá que “definir state”, sobre o qual você pode aprender em State: A Memória de um Componente.
Recap
- Para passar props, adicione-as à JSX, assim como você faria com atributos HTML.
- Para ler props, use a sintaxe de desestruturação
function Avatar({ person, size })
. - Você pode especificar um valor padrão como
size = 100
, o qual é usado para props inexistentes ouundefined
. - Você pode encaminhar todas as props com a sintaxe de espalhamento JSX
<Avatar {...props} />
, mas não abuse! - JSX aninhada como
<Card><Avatar /></Card>
aparecerá como a propchildren
do componenteCard
. - Props podem somente ser lidas e representam um momento específico no tempo: toda renderização recebe uma nova versão de props.
- Você não pode mudar as props. Quando você precisar de interatividade, precisará definir state.
Challenge 1 of 3: Extraia um componente
Este componente Gallery
contém marcação bastante similar para os dois perfis. Extraia um componente Profile
a partir dele para reduzir a duplicação de código. Você precisará escolher quais props passar para ele.
import { getImageUrl } from './utils.js'; export default function Gallery() { return ( <div> <h1>Notable Scientists</h1> <section className="profile"> <h2>Maria Skłodowska-Curie</h2> <img className="avatar" src={getImageUrl('szV5sdG')} alt="Maria Skłodowska-Curie" width={70} height={70} /> <ul> <li> <b>Profession: </b> physicist and chemist </li> <li> <b>Awards: 4 </b> (Nobel Prize in Physics, Nobel Prize in Chemistry, Davy Medal, Matteucci Medal) </li> <li> <b>Discovered: </b> polonium (element) </li> </ul> </section> <section className="profile"> <h2>Katsuko Saruhashi</h2> <img className="avatar" src={getImageUrl('YfeOqp2')} alt="Katsuko Saruhashi" width={70} height={70} /> <ul> <li> <b>Profession: </b> geochemist </li> <li> <b>Awards: 2 </b> (Miyake Prize for geochemistry, Tanaka Prize) </li> <li> <b>Discovered: </b> a method for measuring carbon dioxide in seawater </li> </ul> </section> </div> ); }