20

Цикл внутри JSX в React

14

Я пытаюсь реализовать что-то вроде следующего в React JSX (где ObjectRow — это отдельный компонент):

<tbody>
    for (var i=0; i < numrows; i++) {
        <ObjectRow/>
    } 
</tbody>

Я понимаю, почему это некорректный JSX, так как JSX преобразуется в вызовы функций. Однако, привыкнув к шаблонам и будучи новым в JSX, я не уверен, как реализовать вышеописанное (добавление компонента несколько раз). Как мне это сделать корректно в React?

5 ответ(ов)

1

Для того чтобы отобразить элементы массива в React, вы можете использовать метод map вместе с синтаксисом ES6. Вот пример кода, который иллюстрирует этот подход:

<tbody>
  {items.map(item => <ObjectRow key={item.id} name={item.name} />)} 
</tbody>

Не забудьте указать свойство key, так как оно помогает React отслеживать изменения в списке элементов и повышает производительность рендеринга.

1

Использование функции map для массивов — это очень распространённый способ перебора массива элементов и создания компонентов на их основе в React. Это отличный способ организовать эффективный и аккуратный цикл в JSX. Это не единственный способ сделать это, но это предпочтительный способ.

Не забывайте также о наличии уникального ключа для каждой итерации, как того требуют рекомендации. Функция map создаёт уникальный индекс, начиная с 0, но не рекомендуется использовать созданный индекс; если ваше значение уникально или у него есть уникальный ключ, вы можете использовать их:

<tbody>
  {numrows.map(x => <ObjectRow key={x.id} />)}
</tbody>

Также приведу несколько строк из MDN, если вы не знакомы с функцией map для массивов:

map вызывает предоставленную функцию обратного вызова один раз для каждого элемента в массиве в порядке следования и создаёт новый массив из результатов. Функция обратного вызова вызывается только для индексов массива, которые имеют назначенные значения, включая undefined. Она не вызывается для отсутствующих элементов массива (то есть индексов, которые никогда не были установлены, которые были удалены или для которых никогда не было назначено значение).

Функция обратного вызова вызывается с тремя аргументами: значением элемента, индексом элемента и объектом массива, который перебирается.

Если параметр thisArg передан в метод map, он будет использован как значение this для функции обратного вызова. В противном случае будет использоваться значение undefined. Это значение, в конечном счёте наблюдаемое функцией обратного вызова, определяется в соответствии с обычными правилами определения контекста this, видимого для функции.

map не изменяет массив, на котором он вызывается (хотя функция обратного вызова, если она вызывается, может это сделать).

0

Существует несколько способов решения этой задачи. JSX в конечном итоге компилируется в JavaScript, поэтому, пока вы пишете корректный JavaScript, все будет работать.

Мой ответ направлен на то, чтобы объединить все замечательные способы, уже предложенные здесь:

Если у вас нет массива объектов, а только количество строк:

Внутри блока return создайте Array и используйте Array.prototype.map:

render() {
  return (
    <tbody>
      {Array(numrows).fill(null).map((value, index) => (
        <ObjectRow key={index} />
      ))}
    </tbody>
  );
}

Снаружи блока return используйте обычный цикл for:

render() {
  let rows = [];
  for (let i = 0; i < numrows; i++) {
    rows.push(<ObjectRow key={i} />);
  }
  return (
    <tbody>{rows}</tbody>
  );
}

Используя немедленно вызываемое функциональное выражение:

render() {
  return (
    <tbody>
      {(() => {
        let rows = [];
        for (let i = 0; i < numrows; i++) {
          rows.push(<ObjectRow key={i} />);
        }
        return rows;
      })()}
    </tbody>
  );
}

Если у вас есть массив объектов:

Внутри блока return примените .map() к каждому объекту для создания компонента <ObjectRow>:

render() {
  return (
    <tbody>
      {objectRows.map((row, index) => (
        <ObjectRow key={index} data={row} />
      ))}
    </tbody>
  );
}

Снаружи блока return используйте обычный цикл for:

render() {
  let rows = [];
  for (let i = 0; i < objectRows.length; i++) {
    rows.push(<ObjectRow key={i} data={objectRows[i]} />);
  }
  return (
    <tbody>{rows}</tbody>
  );
}

С использованием немедленно вызываемого функционального выражения:

render() {
  return (
    <tbody>
      {(() => {
        const rows = [];
        for (let i = 0; i < objectRows.length; i++) {
          rows.push(<ObjectRow key={i} data={objectRows[i]} />);
        }
        return rows;
      })()}
    </tbody>
  );
}

Эти подходы позволяют гибко создавать строки на основе количества или массива объектов, что удобно для работы с динамическими данными.

0

Вы также можете вынести код за пределы блока возврата:

render: function() {
    var rows = [];
    for (var i = 0; i < numrows; i++) {
        rows.push(<ObjectRow key={i}/>);
    } 

    return (<tbody>{rows}</tbody>);
}

В данном примере массив rows формируется в цикле, и после этого он передается в блок возвращаемого значения. Таким образом вы можете заранее собрать все необходимые элементы и вернуть их в нужном формате.

0

Если numrows — это массив, то всё очень просто:

<tbody>
   {numrows.map(item => <ObjectRow />)}
</tbody>

Тип данных массива в React значительно лучше. Массив может быть основой для нового массива и поддерживать методы, такие как filter, reduce и т.д.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь