От автора: хотите знать, как создавать циклы в React? Узнайте о JSX и о том, как использовать такие методы, как функция map, для создания цикла внутри React JSX и отображения списка элементов.
О JSX в двух словах
Если вы работали с React раньше, то существует высокая вероятность того, что вы знаете, что такое JSX, или, по крайней мере, слышали о нем. JSX — это пользовательское синтаксическое расширение JavaScript, которое используется для создания разметки с помощью React. Он может немного напоминать вам шаблонизатор, но с JSX вы можете использовать всю мощь JavaScript. Однако помните, что JSX не будет работать напрямую в браузерах и требует шага сборки для преобразования разметки JSX в вызовы функций React.createElement.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// JSX example return ( <div> <button onClick={onClickHandler}>Submit</button> </div> ) // The above will be converted to something like this return React.createElement( "div", {}, React.createElement( "button", { onClick: e => {} }, "Submit" ) ); |
Вы можете узнать об этом больше на сайте React.
Как выполнить в JSX цикл с помощью функции map
Когда я впервые начал работать с React, я довольно рано понял, что не знаю, как перебрать массив и отобразить список элементов. Наиболее распространенный способ сделать это с помощью функции map, которая будет возвращать JSX. Вам редко понадобится цикл, отличный от этого. Ниже вы можете увидеть, как это работает.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import React from ‘react’ const RenderList = props => { const animals = ["Dog", "Bird", "Cat", "Mouse", "Horse"]; return ( <ul> {animals.map(animal => ( <li>{animal}</li> ))} </ul> ); }; |
Вы должны получить список. Однако, если вы посмотрите журнал консоли, то увидите предупреждение типа “Warning: Each child in a list should have a unique key prop”. Каждый раз, когда вы используете цикл, важно предоставить уникальный атрибут key. Причина в том, что React использует эти ключи для отслеживания изменений, добавления или удаления элементов. Ну, мы могли бы просто использовать индекс цикла, не так ли?
1 2 3 4 5 6 7 |
return ( <ul> {animals.map((animal, index) => ( <li key={index}>{animal}</li> ))} </ul> ); |
Добавив ключ, мы больше не получим предупреждений в консоли. Тем не менее, есть еще кое-что, что вам нужно знать. Использование индекса в качестве ключа в определенных ситуациях может привести к другой проблеме и вызвать ошибки.
Почему key важен в циклах?
Как я упоминал ранее, React использует атрибут key для отслеживания внесенных изменений. Представьте себе сценарий, в котором у вас есть список элементов, которые можно переупорядочить. Если в качестве ключей используются индексы, и мы меняем порядок элементов, узнает ли React об этом? Ну, этого может не произойти, так как, хотя порядок элементов в массиве изменился, ключи не изменились. Следовательно, список не будет перерисован.
Так что, как правило, если у вас есть массив, который можно изменить, используйте уникальный идентификатор. Если он недоступен, то создайте его для каждого элемента, прежде чем отобразить список. В противном случае можно использовать индекс для атрибута key.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// Example with an id const RenderList = props => { const animals = [ { id: 1, animal: "Dog" }, { id: 2, animal: "Bird" }, { id: 3, animal: "Cat" }, { id: 4, animal: "Mouse" }, { id: 5, animal: "Horse" } ]; return ( <ul> {animals.map(item => ( <li key={item.id}>{item.animal}</li> ))} </ul> ); }; |
До сих пор мы использовали функцию map непосредственно в выражении return. Однако, если хотите, вы можете сначала использовать переменную для хранения результатов map, а затем отобразить содержимое переменной.
1 2 3 4 5 |
const renderAnimals = animals.map(item => ( <li key={item.id}>{item.animal}</li> )); return <ul>{renderAnimals}</ul>; |
Если хотите, вы можете даже использовать функцию.
1 2 3 4 5 |
const getAnimalsContent = animals => animals.map(item => ( <li key={item.id}>{item.animal}</li> )); return <ul>{getAnimalsContent(animals)}</ul>; |
Использование других циклов в React
В 99,99% случаев я использую функцию map для отображения списка элементов и, честно говоря, не могу вспомнить ни одного сценария, в котором мне понадобился еще один цикл. Тем не менее, вы не привязаны к нему и можете использовать любой цикл для отображения списка. Все это прекрасно работает:
For-of
1 2 3 4 5 6 7 8 9 |
const getAnimalsContent = animals => { let content = []; for (let item of animals) { content.push(<li key={item.id}>{item.animal}</li>); } return content; }; return <ul>{getAnimalsContent(animals)}</ul>; |
For-in
1 2 3 4 5 6 7 8 9 10 |
const getAnimalsContent = animals => { let content = []; for (let idx in animals) { const item = animals[idx]; content.push(<li key={item.id}>{item.animal}</li>); } return content; }; return <ul>{getAnimalsContent(animals)}</ul>; |
For-standard
1 2 3 4 5 6 7 8 9 10 |
const getAnimalsContent = animals => { let content = []; for (let i = 0; i < animals.length; i++) { const item = animals[i]; content.push(<li key={item.id}>{item.animal}</li>); } return content; }; return <ul>{getAnimalsContent(animals)}</ul>; |
Filter
Функция Filter может использоваться вместе с фильтрацией элементов map перед их отображением. Например, в приведенном ниже примере будут отображаться только элементы «Mouse» и «Horse».
1 2 3 4 5 6 7 |
// Filter out any animals that do not contain ‘e’ character. const getAnimalsContent = animals => animals .filter(item => item.animal.includes("e")) .map(item => <li key={item.id}>{item.animal}</li>); return <ul>{getAnimalsContent(animals)}</ul>; |
Reduce
Приведенный выше пример filter можно улучшить с помощью метода reduce, и вместо двух циклов — одного для фильтрации и одного для создания контента JSX — у нас будет только один.
1 2 3 4 5 6 7 8 9 |
const getAnimalsContent = animals => animals.reduce((acc, item) => { if (item.animal.includes("e")) { acc.push(<li key={item.id}>{item.animal}</li>); } return acc; }, []); return <ul>{getAnimalsContent(animals)}</ul>; |
Если по какой-либо причине вы хотите поэкспериментировать, вы можете даже использовать рекурсию для отображения списка. Однако я бы не советовал делать это, и в большинстве случаев вам действительно следует придерживаться функции map.
1 2 3 4 5 6 7 8 |
const getAnimalsContent = (animals, content = []) => { if (!animals.length) return content; const [item, ...restAnimals] = animals; content.push(<li key={item.id}>{item.animal}</li>); return getAnimalsContent(restAnimals, content); }; return <ul>{getAnimalsContent(animals)}</ul>; |
Как вы можете видеть, существует несколько различных способов отображения списка элементов в React. Я надеюсь, что после прочтения этой статьи вы будете более уверенно использовать React и циклы в JSX.
Автор: Thomas Findlay
Источник: //www.telerik.com
Редакция: Команда webformyself.