Edit on GitHub

Listas e chaves

Primeiro, rever como revisar como você transforma listas em JavaScript.

Dado o código abaixo, usamos a função map() para pegar um array de numbers e dobrar seus valores. Nós atribuímos o novo array retornado por map() a variável doubled e depois exibimos no log:

const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((number) => number * 2);
console.log(doubled);

O código irá imprimir [2, 4, 6, 8, 10] no log do console.

Em React, transformar arrys em listas de elements é quase idêntico.

Renderizando múltiplos componentes #

Você pode criar coleções de elementos e incluí-los em JSX usando chaves {}.

Abaixo, nós percorremos pelo array numbers usando a função Javascript map(). Nós retornamos um elemento <li> para cada item. Finalmente, nós atribuímos o array resultante de elementos a constante listItems:

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
  <li>{number}</li>
);

Nós incluímos todo o array listItems dentro de um elemento <ul>, e renderizamos no DOM:

ReactDOM.render(
  <ul>{listItems}</ul>,
  document.getElementById('root')
);

Teste este código no CodePen.

Este código exibe uma lista de números entre 1 e 5.

Componente de lista #

Geralmente você renderiza listas dentro de um componente.

Nós podemos refatorar o exemplo anterior em um componente que aceita um array de numbers e imprime uma lista não ordenada de elementos.

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li>{number}</li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

Quando você executar este código, você receberá um aviso que uma chave deve ser informada para os itens da lista. Uma "key" (chave) é um atributo string especial que você deve incluir quando cria listas de elementos. Nós iremos discutir porque é importante na próxima seção.

Vamos atribuir uma key(chave) para nossos itens dentro de numbers.map() e consertar o problema de chave não existente.

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

Teste este código no CodePen.

Chaves #

Chages ajudam o React a identificar quais itens mudaram, são adicionados, ou são removidos. Chaves devem ser dadas aos elementos dentro do array para fornecer uma identidade estável para os elementos:

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
  <li key={number.toString()}>
    {number}
  </li>
);

A melhor maneira de escolher uma chave é umsar uma string que identifica exclusivamente um item da lista em relação a seus irmãos. Na maioria das vezes você usa IDs de seus dados como chaves:

const todoItems = todos.map((todo) =>
  <li key={todo.id}>
    {todo.text}
  </li>
);

Quando você não tem IDs estáves para renderizar os itens, você deve usar o índice do item como uma chave como último recurso:

const todoItems = todos.map((todo, index) =>
  // Only do this if items have no stable IDs
  <li key={index}>
    {todo.text}
  </li>
);

Nós não recomendamos usar índices para chaves se os itens podem ser reordenados, pois isso seria lento. Você pode ler um explicação detalhada sobre porque chaves são necessárias se estiver interessado.

Extraindo componentes com chaves #

Chaves só fazem sentido no contexto de arrays.

Por exemplo, se você extrair um componente ListItem, você deve manter a chave nos elementos <ListItem /> no array ao invés na raiz do elemento <li> dentro de ListItem em si.

Exemplo: Uso incorreto de chave(key)

function ListItem(props) {
  const value = props.value;
  return (
    // Wrong! There is no need to specify the key here:
    <li key={value.toString()}>
      {value}
    </li>
  );
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    // Wrong! The key should have been specified here:
    <ListItem value={number} />
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

Examplo: Uso correto de chave(key)

function ListItem(props) {
  // Correct! There is no need to specify the key here:
  return <li>{props.value}</li>;
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    // Correct! Key should be specified inside the array.
    <ListItem key={number.toString()}
              value={number} />
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

Teste este código no CodePen.

Uma regra de ouro é que elementos dentro de map() devem ter chaves(keys).

Chaves só devem ser únicas entre seus irmãos #

Chaves usadas dentro de arrays devem ser únicas entre seus irmãos. No entanto, elas não devem ser únicas globalmente. Nós podemos usar a mesma chave para criar dois arrays diferentes:

function Blog(props) {
  const sidebar = (
    <ul>
      {props.posts.map((post) =>
        <li key={post.id}>
          {post.title}
        </li>
      )}
    </ul>
  );
  const content = props.posts.map((post) =>
    <div key={post.id}>
      <h3>{post.title}</h3>
      <p>{post.content}</p>
    </div>
  );
  return (
    <div>
      {sidebar}
      <hr />
      {content}
    </div>
  );
}

const posts = [
  {id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
  {id: 2, title: 'Installation', content: 'You can install React from npm.'}
];
ReactDOM.render(
  <Blog posts={posts} />,
  document.getElementById('root')
);

Teste este código no CodePen.

Chaves servem como uma dica para o React, mas elas não passam para seus componentes. Se você precisar do mesmo valor no seu componente, passe-o explicitamente como uma propriedade com um nome diferente:

const content = posts.map((post) =>
  <Post
    key={post.id}
    id={post.id}
    title={post.title} />
);

Com o exemplo acima, o componente Post pode ler props.id, mas não props.key.

Incorporando map() em JSX #

Nos exemplos acima nós declaramos uma variável listItems separada e incluímos no JSX:

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <ListItem key={number.toString()}
              value={number} />
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

JSX permite incorporar qualquer expressão entre chaves, então nós podemos chamar a função map() diretamente, veja o resultado:

function NumberList(props) {
  const numbers = props.numbers;
  return (
    <ul>
      {numbers.map((number) =>
        <ListItem key={number.toString()}
                  value={number} />
      )}
    </ul>
  );
}

Teste este código no CodePen.

As vezes isso resulta em um código mais claro, mas este estilo pode também ser abusado. Como no JavaScript, cabe a você decidir se vale a pena extrair uma variável para facilitar a leitura. Tenha em mente que se o corpo de map() for muito aninhado, pode ser uma boa hora para extrair para um componente.