Componentes e Props

Componentes permitem que dividas a interface gráfica (UI) em partes independentes, reutilizáveis e que te façam analisar cada parte de forma isolada. Esta página faz uma introdução à ideia de componentes. Podes encontrar uma referência detalhada da API de componentes aqui.

Em conceito, componentes são como funções em JavaScript. Eles aceitam entradas arbitrárias (chamadas “props”) e retornam elementos React descrevendo o que deve aparecer na tela.

Componentes de Função e Classe

A maneira mais simples de definir um componente é escrever uma função JavaScript:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

Esta função é um componente React válido porque aceita um único argumento de objeto “props” (que significa propriedades) com dados e retorna um elemento React. Nós chamamos estes componentes de “componentes de função” porque são literalmente funções JavaScript.

Podes também usar uma classe ES6 para definir um componente:

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

Os dois componentes acima são equivalentes do ponto de vista do React.

Classes tem alguns recursos adicionais que nós discutiremos nas próximas seções. Até lá, nós usaremos componentes de função por serem mais sucintos.

Renderização de um Componente

Anteriormente, nós encontramos apenas elementos React que representam tags do DOM:

const element = <div />;

No entanto, elementos também podem representar componentes definidos pelo utilizador:

const element = <Welcome name="Sara" />;

Quando o React vê um elemento representando um componente definido pelo utilizador, ele passa atributos JSX para esse componente como um único objeto. Nós chamamos esse objeto de “props”.

Por exemplo, esse código renderiza “Hello, Sara” na página:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

const element = <Welcome name="Sara" />;
ReactDOM.render(
  element,
  document.getElementById('root')
);

Try it on CodePen

Vamos recapitular o que acontece neste exemplo:

  1. Nós chamamos ReactDOM.render() com o elemento <Welcome name="Sara" />.
  2. React chama o componente Welcome com {name: 'Sara'} como props.
  3. Nosso componente Welcome retorna um elemento <h1>Hello, Sara</h1> como resultad
  4. React DOM atualiza eficientemente o DOM para corresponder à <h1>Hello, Sara</h1>.

Nota: Sempre comeces os nomes dos componentes com uma letra maiúscula.

O React trata componentes que começam com letras minúsculas como tags do DOM. Por exemplo, <div /> representa uma tag div do HTML, mas <Welcome /> representa um componente e requer que Welcome esteja no escopo.

Para ler mais sobre o raciocínio por trás desta convenção, leia JSX em profundidade.

Composição de Componentes

Componentes podem fazer referência à outros componentes. Isto nos permite usar a mesma abstração de componentes para qualquer nível. Um botão, um formulário, uma caixa de diálogo, uma tela: em aplicações em React, todos esses são normalmente expressos como componentes.

Por exemplo, nós podemos criar um componente App que renderiza Welcome várias vezes:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

function App() {
  return (
    <div>
      <Welcome name="Sara" />
      <Welcome name="Cahal" />
      <Welcome name="Edite" />
    </div>
  );
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

Try it on CodePen

Geralmente, novas aplicações em React têm um único componente App no topo. Contudo, se integrares o React em uma aplicação existente, podes começar de baixo para cima com um componente pequeno como o Button e gradualmente chegar ao topo da hierarquia de componentes.

Extração de Componentes

Não tenhas receio de dividir componentes em componentes menores.

Por exemplo, considere esse componente Comment:

function Comment(props) {
  return (
    <div className="Comment">
      <div className="UserInfo">
        <img className="Avatar"
          src={props.author.avatarUrl}
          alt={props.author.name}
        />
        <div className="UserInfo-name">
          {props.author.name}
        </div>
      </div>
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

Try it on CodePen

Ele aceita author (um objeto), text (uma string) e date (uma data) como props e descreve um comentário em um website de mídia social.

Esse componente pode ser difícil de alterar por causa de toda ramificação. Também é difícil reutilizar suas partes individuais. Vamos extrair alguns componentes dele.

Primeiro, nós vamos extrair Avatar:

function Avatar(props) {
  return (
    <img className="Avatar"
      src={props.user.avatarUrl}
      alt={props.user.name}
    />
  );
}

O Avatar não precisa saber que está a ser renderizado dentro do Comment. É por isto que nós demos ao seu prop um nome mais genérico: user em vez de author.

Nós recomendamos nomear props a partir do ponto de vista do próprio componente ao invés do contexto em que ele está a ser usado.

Agora nós podemos simplificar Comment um pouco mais:

function Comment(props) {
  return (
    <div className="Comment">
      <div className="UserInfo">
        <Avatar user={props.author} />
        <div className="UserInfo-name">
          {props.author.name}
        </div>
      </div>
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

Em seguida, nós vamos extrair o componente UserInfo que renderiza um Avatar ao lado do nome do utilizador:

function UserInfo(props) {
  return (
    <div className="UserInfo">
      <Avatar user={props.user} />
      <div className="UserInfo-name">
        {props.user.name}
      </div>
    </div>
  );
}

Isto nos permite simplificar Comment ainda mais:

function Comment(props) {
  return (
    <div className="Comment">
      <UserInfo user={props.author} />
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

Try it on CodePen

Extrair componentes pode parecer um trabalho pesado no começo, mas ter uma conjunto de componentes reutilizáveis compensa em aplicações maiores. Uma boa regra é, se uma parte da sua UI for usada várias vezes (Button, Panel, Avatar) ou for complexa o suficiente por si só (App, FeedStory, Comment), é uma boa candidata a se tornar um componente reutilizável.

Props são somente leitura

Independente de declarares um componente como uma função ou uma classe, ele nunca deve modificar seus próprios props. Considera esta função sum:

function sum(a, b) {
  return a + b;
}

Tais funções são chamadas “puras” porque elas não tentam alterar suas entradas e sempre retornam o mesmo resultado para as mesmas entradas.

Em contraste, esta função é impura porque altera sua própria entrada:

function withdraw(account, amount) {
  account.total -= amount;
}

React é bastante flexível mas tem uma única regra estrita:

Todos os componentes em React tem que agir como funções puras em relação ao seus props.

Obviamente, as UIs de aplicações são dinâmicas e mudam com o tempo. Na próxima seção, nós vamos introduzir um novo conceito de “estado” (state). O state permite aos componentes React alterar sua saída ao longo do tempo em resposta a ações do utilizador, respostas de rede e quaisquer outras coisas, sem violar essa regra.