Renderizando Listas
É comum a necessidade de se exibir vários componentes semelhantes a partir de uma coleção de dados. Você pode usar os métodos de array JavaScript para manipular um array de dados. Nessa página, você usará filter()
e map()
com o React para filtrar e transformar seu array de dados em um array de componentes.
Você aprenderá
- Como renderizar componentes a partir de um array usando
map()
do JavaScript - Como renderizar apenas componentes específicos usando
filter()
do JavaScript - Quando e por que usar as keys do React
Renderizando dados de arrays
Digamos que você tenha uma lista de informações.
<ul>
<li>Creola Katherine Johnson: mathematician</li>
<li>Mario José Molina-Pasquel Henríquez: chemist</li>
<li>Mohammad Abdus Salam: physicist</li>
<li>Percy Lavon Julian: chemist</li>
<li>Subrahmanyan Chandrasekhar: astrophysicist</li>
</ul>
As únicas diferenças entre os itens da lista são seus conteúdos, seus dados. Você comumente precisará exibir diversas instâncias do mesmo componente usando dados diferentes ao construir interfaces: de listas de comentários a galerias de fotos de perfil. Nestas situações, você pode armazenar esses dados em objetos ou arrays JavaScript e usar métodos como map()
e filter()
para renderizar listas de componentes a partir deles.
Aqui está um breve exemplo de como gerar uma lista de itens a partir de um array:
- Mova os dados para um array:
const people = [
'Creola Katherine Johnson: mathematician',
'Mario José Molina-Pasquel Henríquez: chemist',
'Mohammad Abdus Salam: physicist',
'Percy Lavon Julian: chemist',
'Subrahmanyan Chandrasekhar: astrophysicist'
];
- Mapeie os membros de
people
a um novo array de nós JSX,listItems
:
const listItems = people.map(person => <li>{person}</li>);
- Retorne
listItems
do seu componente dentro de uma<ul>
:
return <ul>{listItems}</ul>;
Esse é o resultado:
const people = [ 'Creola Katherine Johnson: mathematician', 'Mario José Molina-Pasquel Henríquez: chemist', 'Mohammad Abdus Salam: physicist', 'Percy Lavon Julian: chemist', 'Subrahmanyan Chandrasekhar: astrophysicist' ]; export default function List() { const listItems = people.map(person => <li>{person}</li> ); return <ul>{listItems}</ul>; }
Perceba que a sandbox acima exibe um erro no console:
Mais tarde nessa página, você aprenderá como corrigir este erro. Mas antes, vamos estruturar os seus dados um pouco mais.
Filtrando arrays de itens
Esses dados podem ser estruturados ainda mais.
const people = [{
id: 0,
name: 'Creola Katherine Johnson',
profession: 'mathematician',
}, {
id: 1,
name: 'Mario José Molina-Pasquel Henríquez',
profession: 'chemist',
}, {
id: 2,
name: 'Mohammad Abdus Salam',
profession: 'physicist',
}, {
name: 'Percy Lavon Julian',
profession: 'chemist',
}, {
name: 'Subrahmanyan Chandrasekhar',
profession: 'astrophysicist',
}];
Vamos supor que você queira exibir somente as pessoas cuja profissão seja 'chemist'
. Neste caso, voce pode usar o método filter()
do JavaScript para retornar apenas essas pessoas. Este método recebe um array de itens, os quais são submetidos a um “teste” (uma função que retorna true
ou false
), e retorna um novo array contendo apenas aqueles itens os quais passaram no teste (retornaram true
).
Você quer apenas os itens onde profession
seja 'chemist'
. A função “teste” para isto ficaria assim (person) => person.profession === 'chemist'
. Veja como juntar tudo isso:
- Crie um novo array contendo apenas pessoas cuja profissão é “chemist”,
chemists
, chamandofilter()
empeople
e filtrando porperson.profession === 'chemist'
:
const chemists = people.filter(person =>
person.profession === 'chemist'
);
- Agora mapeie sobre
chemists
:
const listItems = chemists.map(person =>
<li>
<img
src={getImageUrl(person)}
alt={person.name}
/>
<p>
<b>{person.name}:</b>
{' ' + person.profession + ' '}
known for {person.accomplishment}
</p>
</li>
);
- Por fim, retorne
listItems
em seu componente:
return <ul>{listItems}</ul>;
import { people } from './data.js'; import { getImageUrl } from './utils.js'; export default function List() { const chemists = people.filter(person => person.profession === 'chemist' ); const listItems = chemists.map(person => <li> <img src={getImageUrl(person)} alt={person.name} /> <p> <b>{person.name}:</b> {' ' + person.profession + ' '} known for {person.accomplishment} </p> </li> ); return <ul>{listItems}</ul>; }
Mantendo itens em ordem com key
Perceba que todas as sandboxes acima exibem um erro no console:
Você precisa dar a cada item do array uma key
— uma string ou um número que o identifique unicamente dentre os demais itens naquele array:
<li key={person.id}>...</li>
Keys dizem ao React a qual item do array cada componente corresponde, para que ele possa combiná-los mais tarde. Isso se torna importante se os itens do seu array podem se mover (por exemplo, ao ser ordenado), serem inseridos, ou serem removidos. Uma key
bem escolhida ajuda o React a identificar o que exatamente aconteceu, e fazer as atualizações corretas à árvore da DOM.
Em vez de gerar keys em tempo real, você deve incluí-las em seus dados:
export const people = [{ id: 0, // Usado no JSX como key name: 'Creola Katherine Johnson', profession: 'mathematician', accomplishment: 'spaceflight calculations', imageId: 'MK3eW3A' }, { id: 1, // Usado no JSX como key name: 'Mario José Molina-Pasquel Henríquez', profession: 'chemist', accomplishment: 'discovery of Arctic ozone hole', imageId: 'mynHUSa' }, { id: 2, // Usado no JSX como key name: 'Mohammad Abdus Salam', profession: 'physicist', accomplishment: 'electromagnetism theory', imageId: 'bE7W1ji' }, { id: 3, // Usado no JSX como key name: 'Percy Lavon Julian', profession: 'chemist', accomplishment: 'pioneering cortisone drugs, steroids and birth control pills', imageId: 'IOjWm71' }, { id: 4, // Usado no JSX como key name: 'Subrahmanyan Chandrasekhar', profession: 'astrophysicist', accomplishment: 'white dwarf star mass calculations', imageId: 'lrWQx8l' }];
Deep Dive
O que fazer quando cada item precisa renderizar não um, mas múltiplos nós da DOM?
A sintaxe abreviada <>...</>
Fragment não deixará com que você passe uma key, por conta disto você precisa agrupá-los em uma única <div>
, ou então usar a um pouco mais longa e mais explícita sintaxe <Fragment>
:
import { Fragment } from 'react';
// ...
const listItems = people.map(person =>
<Fragment key={person.id}>
<h1>{person.name}</h1>
<p>{person.bio}</p>
</Fragment>
);
Fragmentos desaparecem da DOM, então isto irá produzir uma lista plana de <h1>
, <p>
, <h1>
, <p>
, e assim por diante.
Onde conseguir sua key
As chaves podem vir de diferentes fontes de dados:
- Dados de uma base de dados: Se seus dados estão vindo de uma base de dados, você pode usar as keys/IDs desta, os quais são únicos por natureza.
- Dados gerados localmente: Se seus dados são gerados e persistidos localmente (por exemplo, anotações em um aplicativo de notas), use um contador incremental,
crypto.randomUUID()
ou um biblioteca como auuid
ao criar itens.
Regras das keys
- Keys devem ser únicas entre suas irmãs. Entretanto, é tranquilo usar as mesmas chaves para nós JSX em arrays diferentes.
- Keys não devem mudar caso contrário, isso vai contra o seu propósito! Não as gere durante a renderização.
Por que o React precisa de keys?
Imagine que os arquivos em sua área de trabalho não tivessem nomes. Em vez disso, você teria que se referir a eles pela sua ordem — o primeiro arquivo, o segundo arquivo, e assim por diante. Isto poderia funcionar em um primeiro momento, porém uma vez que você exclua um arquivo, as coisas iriam ficar confusas. O segundo arquivo se tornaria o primeiro, o terceiro arquivo se tornaria o segundo e assim por diante.
Nomes de arquivo em uma pasta e keys JSX em um array servem um propósito similar. Eles permitem com que nós identifiquemos unicamente um item entre seus irmãos. Uma key bem escolhida fornece mais informação que uma posição dentro do array. Mesmo que a posição mude por conta de uma reordenação, a key
permite que o React identifique o item durante seu ciclo de vida.
Recap
Nessa página você aprendeu:
- Como mover dados para fora de componentes e para dentro de estruturas como arrays ou objetos.
- Como gerar conjuntos de componentes similares com o
map()
do JavaScript. - Como criar arrays de itens filtrados com o
filter()
do JavaScript. - Porquê e como definir
key
em cada componente dentre uma coleção para que o React possa acompanhar cada um deles mesmo se sua posição ou dados mudem.
Challenge 1 of 4: Separando uma lista em duas
Esse exemplo mostra uma lista de todas as pessoas.
Altere-o para exibir duas listas separadas uma após a outra: Químicos e Outras Profissões. Como antes, você pode determinar se uma pessoa é um “químico” checando se person.profession === 'chemist'
.
import { people } from './data.js'; import { getImageUrl } from './utils.js'; export default function List() { const listItems = people.map(person => <li key={person.id}> <img src={getImageUrl(person)} alt={person.name} /> <p> <b>{person.name}:</b> {' ' + person.profession + ' '} known for {person.accomplishment} </p> </li> ); return ( <article> <h1>Scientists</h1> <ul>{listItems}</ul> </article> ); }