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}
/>
);
}

Note

Se as chaves duplas depois de person= confundirem você, lembre-se que elas são meramente um objeto dentro das chaves da JSX.

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.

Pitfall

Não esqueça o par de { e } chaves dentro de ( e ) ao declarar props:

function Avatar({ person, size }) {
// ...
}

Esta sintaxe é chamada de “desestruturação” e é equivalente a ler propriedades de um parâmetro de função:

function Avatar(props) {
let person = props.person;
let size = props.size;
// ...
}

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.

A puzzle-like Card tile with a slot for "children" pieces like text and Avatar

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 ou undefined.
  • 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 prop children do componente Card.
  • 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 (chemical 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>
  );
}