Петля внутри React JSX

1279

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

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

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

Бен Робертс
источник
38
Важно отметить, что в JSX вам нужны теги {} вокруг вашего синтаксиса JavaScript. Это может помочь facebook.github.io/react/docs/… .
Исаия Грей,
30
let todos = this.props.todos.map((todo) => {return <h1>{todo.title}</h1>})
OverCoder
@OverCoder, зачем вам помещать весь return в тег {}, это будет => return <h1> {todo.title} </ h1> Не так ли?
Правин Пудель
1
@pravinpoudel на самом деле этот ответ старый, больше похож на let todos = this.props.todos.map(t => <h1>{t.title}</h1>):)
OverCoder

Ответы:

1207

Думайте об этом, как будто вы просто вызываете функции JavaScript. Вы не можете использовать forцикл, куда будут идти аргументы для вызова функции:

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

Посмотрите, как функции tbodyпередается forцикл в качестве аргумента, и, конечно, это синтаксическая ошибка.

Но вы можете создать массив, а затем передать его в качестве аргумента:

var rows = [];
for (var i = 0; i < numrows; i++) {
    rows.push(ObjectRow());
}
return tbody(rows);

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

var rows = [];
for (var i = 0; i < numrows; i++) {
    // note: we add a key prop here to allow react to uniquely identify each
    // element in this array. see: https://reactjs.org/docs/lists-and-keys.html
    rows.push(<ObjectRow key={i} />);
}
return <tbody>{rows}</tbody>;

Между прочим, мой пример JavaScript почти точно то, во что превращается этот пример JSX. Поиграйте с Babel REPL, чтобы понять, как работает JSX.

Софи Альперт
источник
3
Возможно, компилятор изменился, так как этот пример не компилируется в компиляторе jsx , но использование map, как в ответе FakeRainBrigand ниже, похоже, компилируется правильно.
Рав
9
Я могу обещать, что последний пример по-прежнему правильно компилируется на последнем компиляторе JSX.
Софи Альперт,
3
Это хорошо работает. Ответ FakeRainBrigand работает для простой итерации массива, но этот ответ является обязательным для сценариев, где вы не можете использовать map(например, у вас нет коллекции, хранящейся в переменной).
Кельвин
53
React должен эффективно обновлять dom, в этом случае родитель должен назначить a keyкаждому ребенку. REF: facebook.github.io/react/docs/…
qsun
7
Этот пример будет работать, но он пропускает некоторые важные биты, такие как keyсвойство, а также стиль кода, который на самом деле не используется в базах кода React. Пожалуйста, рассмотрите этот ответ stackoverflow.com/questions/22876978/loop-inside-react-jsx/… как правильный.
оконечников
867

Не уверен, что это сработает для вашей ситуации, но часто карта - хороший ответ.

Если это был ваш код с циклом for:

<tbody>
    for (var i=0; i < objects.length; i++) {
        <ObjectRow obj={objects[i]} key={i}>
    } 
</tbody>

Вы можете написать это так с картой :

<tbody>
    {objects.map(function(object, i){
        return <ObjectRow obj={object} key={i} />;
    })}
</tbody>

Синтаксис ES6:

<tbody>
    {objects.map((object, i) => <ObjectRow obj={object} key={i} />)}
</tbody>
разбойник
источник
44
Карта имеет больше смысла, если итератор является массивом; Цикл for подходит, если это число.
Код Whisperer
26
<tbody>{objects.map((o, i) => <ObjectRow obj={o} key={i}/>}</tbody>используя поддержку Reactify ES6 или Babel.
Distortum
3
+1. Я даже использую это с ul (неупорядоченный список). <ul> {objects.map((object:string,i:number)=>{ return <li>{object}</li> })} </ul>с использованием TypeScript
Роберто С. Наварро
6
это здорово, но вы не можете нанести на карту объект ... для этого я бы использовалfor..in
Damon
4
Имейте в виду, что порядок использования ключей является произвольным при использовании Object.keys. Я считаю, что хранение порядка ключей отдельно работает хорошо, а также, при необходимости, порядок на литерале объекта. Это позволяет мне писать код вродеthis.props.order.map((k)=><ObjectRow key={k} {...this.props.items[k]} />)
tgrrr
444

Если у вас еще нет массива, map()которому нравится ответ @ FakeRainBrigand, и вы хотите вставить его так, чтобы компоновка источника соответствовала выводу ближе, чем ответ @ SophieAlpert:

С синтаксисом ES2015 (ES6) (функции разворота и стрелок)

http://plnkr.co/edit/mfqFWODVy8dKQQOkIEGV?p=preview

<tbody>
  {[...Array(10)].map((x, i) =>
    <ObjectRow key={i} />
  )}
</tbody>

На странице caveats говорится, что Array.fromэто требуется для распространения, но в настоящее время ( v5.8.23) этого не происходит при распространении фактического Array. У меня есть проблема с документацией, чтобы прояснить это. Но используйте на свой страх и риск или polyfill.

Ваниль ES5

Array.apply

<tbody>
  {Array.apply(0, Array(10)).map(function (x, i) {
    return <ObjectRow key={i} />;
  })}
</tbody>

Встроенный IIFE

http://plnkr.co/edit/4kQjdTzd4w69g8Suu2hT?p=preview

<tbody>
  {(function (rows, i, len) {
    while (++i <= len) {
      rows.push(<ObjectRow key={i} />)
    }
    return rows;
  })([], 0, 10)}
</tbody>

Сочетание приемов из других ответов

Держите исходный макет, соответствующий выходу, но сделайте встроенную часть более компактной:

render: function () {
  var rows = [], i = 0, len = 10;
  while (++i <= len) rows.push(i);

  return (
    <tbody>
      {rows.map(function (i) {
        return <ObjectRow key={i} index={i} />;
      })}
    </tbody>
  );
}

С синтаксисом и Arrayметодами ES2015

С этим Array.prototype.fillвы можете сделать это в качестве альтернативы использованию спреда, как показано выше:

<tbody>
  {Array(10).fill(1).map((el, i) =>
    <ObjectRow key={i} />
  )}
</tbody>

(Я думаю, что вы могли бы опустить любой аргумент fill(), но я не на 100% об этом.) Спасибо @FakeRainBrigand за исправление моей ошибки в более ранней версии fill()решения (см. Ревизии).

key

Во всех случаях keyattr снимает предупреждение с помощью сборки разработки, но недоступен для ребенка. Вы можете передать дополнительный атрибут, если хотите, чтобы индекс имелся у ребенка. Смотрите списки и ключи для обсуждения.

JMM
источник
2
Как насчет yield? Вставка элементов в промежуточный массив выглядит некрасиво, когда у нас есть генераторы. Они работают?
mpen
2
@ Марк Я не знаю, что генераторы действительно применимы здесь. Ключевым моментом для этого в контексте JSX является выражение, которое возвращает массив. Поэтому, если вы собираетесь использовать генератор каким-либо образом, вы, вероятно, все равно распространите его, и он, вероятно, будет более многословным, чем решения на основе ES2015.
JMM
2
Как это более многословно? И почему JSX не принимает итеративные, а не только массивы?
mpen
2
@Mark Это действительно менее многословно, чем пример (ES5) IIFE, который я использовал, но он значительно более многословен, чем [...Array(x)].map(() => <El />))версия, которая, на мой взгляд, самая элегантная и почему я ее показал. Re: второй вопрос, это отличный момент. Похоже, в JSX нет ничего, что могло бы помешать этому, поэтому это зависит от того, что React или другой потребитель преобразованного JSX делает с аргументами дочерних элементов, чего я не мог сказать, не глядя на источник. Ты знаешь? Это интригующий вопрос.
JMM
3
@corysimmons Круто, спасибо за информацию fill(). Теперь я помню, что причиной, по которой я колебался, является вопрос о том, как необязательность параметров указывается в спецификации ES (придется рассмотреть это когда-нибудь). Запятая - это просто способ исключить элемент массива - в данном случае первый. Вы можете сделать это, если вы хотите, чтобы индексы были с 1..length массива, который вы распространяете, а не 0..length-1 массива расширения (потому что исключенные элементы просто вносят вклад в длину массива и не не имеет соответствующего свойства).
JMM
85

Просто с помощью метода map Array с синтаксисом ES6:

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

Не забывайте keyсобственность.

danielfeelfine
источник
Я добавляю случайный ключ 'Math.random ()' вместо id, он не работает нормально, когда setState внутри детей, есть идеи почему?
Оливер Д
82

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

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

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

Кроме того, несколько строк из MDN, если вы не знакомы с функцией map в Array:

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

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

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

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

Алиреза
источник
Array#mapне асинхронно!
Philraj
52

Если вы уже используете lodash, _.timesфункция удобна.

import React, { Component } from 'react';
import Select from './Select';
import _ from 'lodash';

export default class App extends Component {
    render() {
        return (
            <div className="container">
                <ol>
                    {_.times(3, i =>
                        <li key={i}>
                            <Select onSelect={this.onSelect}>
                                <option value="1">bacon</option>
                                <option value="2">cheez</option>
                            </Select>
                        </li>
                    )}
                </ol>
            </div>
        );
    }
}
mpen
источник
1
Array.prototype.map может быть отличным вариантом, если вы не включаете такую ​​библиотеку, как lodash. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… .
Исаия Грей,
1
@IsaiahGrey Только если у вас уже есть массив. Иногда вы просто хотите повторить вещи несколько раз.
Мпен
1
конечно же! Много разных подходов наверняка в зависимости от фактических данных. Я обнаружил, что чаще всего в нашем процессе разработки мы смогли вписать карту из-за того, как моделируются данные. Отличный пример использования lodash! Кстати, вы используете синтаксис инициализатора свойства для привязки ваших методов к вашим компонентам?
Исаия Грей,
4
@IsaiahGrey Я думаю, что они просто называются определениями методов
ES6
41

Вы также можете извлечь вне блока возврата:

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

    return (<tbody>{rows}</tbody>);
}
Брэндон Сибейтокгонг
источник
34

Я знаю, что это старый поток, но вы можете проверить React Templates , который позволяет вам использовать шаблоны в стиле jsx в реагировать с несколькими директивами (такими как rt-repeat).

Ваш пример, если бы вы использовали ответные шаблоны, был бы:

<tbody>
     <ObjectRow rt-repeat="obj in objects"/>
</tbody>
Etai
источник
Почему используется дополнительная библиотека, в то время как обычный javascript уже предоставил решение с различными видами цикла for или методом Array.prototype.map для решения проблемы? Я сам уже использовал оба простых способа javascript в моем текущем проекте, которые работают хорошо. Наличие привычки использовать простые способы javascript всегда, когда это возможно, помогает мне улучшить свои навыки в javascript. Я использую дополнительные библиотеки только тогда, когда кажется, что трудно найти решения для определенных проблем, таких как маршрутизация с React-Router.
Lex Soft
27

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

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

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

внутри returnблока, создавая Arrayи используя Array.prototype.map:

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

вне returnблока просто используйте обычный цикл for для JavaScript:

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 для JavaScript:

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>
  );
}
Яншун Тай
источник
2
Хорошие ответы: различные техники, все используют только простой javascript, который демонстрирует мощь javascript благодаря различным способам выполнения похожих задач.
Lex Soft
24

Если Numrows это массив, и это очень просто.

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

Тип данных массива в React намного лучше, массив может поддерживать новый массив и поддерживать фильтрацию, уменьшение и т. Д.

Люлин
источник
Это не приличный ответ, так как он не использует ключ.
kojow7
21

Есть несколько ответов, указывающих на использование этого mapутверждения. Вот полный пример использования итератора в рамках FeatureList компоненты к списку Feature компонентов на основе структуры данных JSON под названием функция .

const FeatureList = ({ features, onClickFeature, onClickLikes }) => (
  <div className="feature-list">
    {features.map(feature =>
      <Feature
        key={feature.id}
        {...feature}
        onClickFeature={() => onClickFeature(feature.id)}
        onClickLikes={() => onClickLikes(feature.id)}
      />
    )}
  </div>
); 

Вы можете просмотреть полный код FeatureList на GitHub. Особенности приспособление перечислены здесь .

Манав Сегал
источник
При работе с данными JSON, например при извлечении данных из базы данных с использованием API выборки, я полагаюсь на использование метода Array.prototype.map. Это удобный и проверенный способ для этой цели.
Lex Soft
17

Чтобы выполнить цикл несколько раз и вернуться, вы можете добиться этого с помощью fromи map:

<tbody>
  {
    Array.from(Array(i)).map(() => <ObjectRow />)
  }
</tbody>

где i = number of times


Если вы хотите назначить уникальные идентификаторы ключей в визуализируемых компонентах, вы можете использовать их, React.Children.toArrayкак предложено в документации React.

React.Children.toArray

Возвращает дочернюю непрозрачную структуру данных в виде плоского массива с ключами, назначенными каждому дочернему элементу. Полезно, если вы хотите манипулировать коллекциями дочерних элементов в ваших методах рендеринга, особенно если вы хотите переупорядочить или нарезать this.props.children перед его передачей.

Замечания:

React.Children.toArray()изменяет ключи, чтобы сохранить семантику вложенных массивов при сглаживании списков дочерних элементов. То есть, toArray ставит префикс перед каждым ключом в возвращаемом массиве, так что ключ каждого элемента ограничивается входным массивом, содержащим его.

<tbody>
  {
    React.Children.toArray(
      Array.from(Array(i)).map(() => <ObjectRow />)
    )
  }
</tbody>
Джи Мок
источник
17

Если вы решили преобразовать это внутри возвращение () в визуализации метод, самый простой вариант будет использовать карту () метод. Сопоставьте ваш массив с синтаксисом JSX с помощью функции map (), как показано ниже ( используется синтаксис ES6 ).


Внутри родительского компонента :

<tbody>
   { objectArray.map(object => <ObjectRow key={object.id} object={object.value}>) }
</tbody>

Обратите внимание на keyатрибут, добавленный к вашему дочернему компоненту. Если вы не указали ключевой атрибут, вы можете увидеть следующее предупреждение на своей консоли.

Предупреждение: каждый дочерний элемент в массиве или итераторе должен иметь уникальную «ключевую» опору.

Примечание. Одна распространенная ошибка, которую делают люди, - это использование в indexкачестве ключа при итерации, использование indexэлемента в качестве ключа является анти-паттерном, и вы можете прочитать больше об этом здесь . Короче говоря, если это НЕ статический список, никогда не используйте его в indexкачестве ключа.


Теперь в компоненте ObjectRow вы можете получить доступ к объекту из его свойств.

Внутри компонента ObjectRow

const { object } = this.props

или

const object = this.props.object

Это должно получить вам объект, который вы передали из родительского компонента в переменную objectв компоненте ObjectRow . Теперь вы можете выплевывать значения в этом объекте в соответствии с вашей целью.


Ссылки :

метод map () в Javascript

ECMA Script 6 или ES6

bharadhwaj
источник
16

скажем, у нас есть массив элементов в вашем состоянии:

[{name: "item1", id: 1}, {name: "item2", id: 2}, {name: "item3", id: 3}]

<tbody>
    {this.state.items.map((item) => {
        <ObjectRow key={item.id} name={item.name} />
    })} 
</tbody>
Ян Франц Палнгипанг
источник
Я думаю, что вам, возможно, придется избавиться от {} после карты (предмета), которая, казалось, сработала для меня.
Ян
15

Возможность ES2015 / Babel - использовать функцию генератора для создания массива JSX:

function* jsxLoop(times, callback)
{
    for(var i = 0; i < times; ++i)
        yield callback(i);
}

...

<tbody>
    {[...jsxLoop(numrows, i =>
        <ObjectRow key={i}/>
    )]}
</tbody>
Дэвид К Хоган
источник
15

... Или вы также можете подготовить массив объектов и сопоставить его с функцией, чтобы получить желаемый результат. Я предпочитаю это, потому что это помогает мне поддерживать хорошую практику кодирования без логики в возвращении рендера.

render() {
const mapItem = [];
for(let i =0;i<item.length;i++) 
  mapItem.push(i);
const singleItem => (item, index) {
 // item the single item in the array 
 // the index of the item in the array
 // can implement any logic here
 return (
  <ObjectRow/>
)

}
  return(
   <tbody>{mapItem.map(singleItem)}</tbody>
  )
}
Рафи Уд Даула Рефат
источник
15

Просто используйте .map()для циклического просмотра вашей коллекции и возврата <ObjectRow>предметов с реквизитом из каждой итерации.

Предполагая, objectsчто это массив где-то ...

<tbody>
  { objects.map((obj, index) => <ObjectRow obj={ obj } key={ index }/> ) }
</tbody>
Джошуа Майкл Вагонер
источник
15

ES2015 Array.from с функцией карты + клавиша

Если у вас ничего нет, .map()вы можете использовать Array.from()эту mapфункцию для повторения элементов:

<tbody>
  {Array.from({ length: 5 }, (value, key) => <ObjectRow key={key} />)}
</tbody>
Do Async
источник
15

Я использую это:

gridItems = this.state.applications.map(app =>
          <ApplicationItem key={app.Id} app={app } />
);

PS: никогда не забывайте ключ, иначе у вас будет много предупреждений!

JC
источник
Или используйте индекс массива, если ваши элементы не имеют .Idсвойства, напримерitems.map( (item, index) => <Foo key={index}>{item}</Foo>
kontur
13

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

Так что я бы, наверное, сделал что-то вроде:

import _ from 'lodash';

...

const TableBody = ({ objects }) => {
  const objectRows = objects.map(obj => <ObjectRow object={obj} />);      

  return <tbody>{objectRows}</tbody>;
} 

По общему признанию, это такой небольшой объем кода, что его вставка может работать нормально.

Адам Донахью
источник
Большой поклонник карты lodash для итерации по объектам. Я бы хотел, import { map } from 'lodash'чтобы вы не импортировали все функции lodash, если они вам не нужны.
Stretch0
В наши дни нам даже не нужна карта lodash - просто карта над массивом напрямую.
Адам Донахью
Да, но вы не можете перебрать объект с помощью es6 map(), только массивы. Это то, что я говорил, lodash хорош для зацикливания объекта.
Stretch0
Я думал, что вы имели objectsв виду, как в списке вещей, моя ошибка.
Адам Донахью
12

Вы, конечно, можете решить с помощью .map, как подсказывает другой ответ. Если вы уже используете babel, вы можете подумать об использовании операторов jsx-control. Они требуют небольшой настройки, но я думаю, что это стоит с точки зрения читабельности (особенно для нереагирующего разработчика). Если вы используете linter, есть также eslint-plugin-jsx-control-инструкции

Юрго Боэмо
источник
12

Ваш JSX-код скомпилируется в чистый код JavaScript, любые теги будут заменены ReactElementобъектами. В JavaScript вы не можете вызывать функцию несколько раз для сбора возвращаемых переменных.

Это недопустимо, единственный способ - использовать массив для хранения возвращаемых функцией переменных.

Или вы можете использовать, Array.prototype.mapкоторый доступен начиная с JavaScript ES5, чтобы справиться с этой ситуацией.

Может быть, мы можем написать другой компилятор для воссоздания нового синтаксиса JSX для реализации функции повтора, как в Angularng-repeat .

hlissnake
источник
12

Это можно сделать несколькими способами.

  1. Как указано выше, перед returnсохранением всех элементов в массиве
  2. Петля внутри return

    Способ 1

     let container =[];
        let arr = [1,2,3] //can be anything array, object 
    
        arr.forEach((val,index)=>{
          container.push(<div key={index}>
                         val
                         </div>)
            /** 
            * 1. All loop generated elements require a key 
            * 2. only one parent element can be placed in Array
            * e.g. container.push(<div key={index}>
                                        val
                                  </div>
                                  <div>
                                  this will throw error
                                  </div>  
                                )
            **/   
        });
        return (
          <div>
             <div>any things goes here</div>
             <div>{container}</div>
          </div>
        )

    Способ 2

       return(
         <div>
         <div>any things goes here</div>
         <div>
            {(()=>{
              let container =[];
              let arr = [1,2,3] //can be anything array, object 
              arr.forEach((val,index)=>{
                container.push(<div key={index}>
                               val
                               </div>)
                             });
                        return container;     
            })()}
    
         </div>
      </div>
    )
abhirathore2006
источник
Да. В моем текущем проекте я использую метод 1, т.е. используя метод Array.prototype, метод forEach () для создания элемента выбора HTML, который заполняется данными из базы данных. Однако я, скорее всего, заменю их методом Array.prototype.map (), так как метод map выглядит более компактным (меньше кода).
Lex Soft
10

Вот простое решение для этого.

var Object_rows=[];
for (var i=0; i < numrows; i++) {
    Object_rows.push(<ObjectRow/>)
} 
<tbody>
  {Object_rows}
</tbody>

Нет необходимости в отображении и сложном коде. Вам просто нужно поместить строки в массив и вернуть значения для его визуализации.

Javasamurai
источник
При создании html-элемента select мне в первую очередь пришла эта похожая техника, поэтому я использовал ее, хотя я использую метод forEach (). Но когда я перечитал документ React по темам списков и ключей, я обнаружил, что они используют метод map (), что также показано здесь несколькими ответами. Это заставляет меня думать, что это предпочтительный способ. Я согласен, так как выглядит более компактно (меньше кода).
Lex Soft
9

Поскольку вы пишете синтаксис Javascript внутри JSX-кода, вам нужно заключить Javascript в фигурные скобки.

row = () => {
   var rows = [];
   for (let i = 0; i<numrows; i++) {
       rows.push(<ObjectRow/>);
   }
   return rows;
}
<tbody>
{this.row()}  
</tbody>
Рохит Джиндал
источник
9

Вот пример из документа React: JavaScript-выражения как дети

function Item(props) {
  return <li>{props.message}</li>;
}

function TodoList() {
  const todos = ['finish doc', 'submit pr', 'nag dan to review'];
  return (
    <ul>
      {todos.map((message) => <Item key={message} message={message} />)}
    </ul>
  );
}

как ваш случай, я предлагаю написать так:

function render() {
  return (
    <tbody>
      {numrows.map((roe, index) => <ObjectRow key={index} />)}
    </tbody>
  );
}

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

Синка Ли
источник
9

Я использую это как

<tbody>
  { numrows ? (
     numrows.map(obj => { return <ObjectRow /> }) 
    ) : null
  }
</tbody>
Сампатх
источник
8

Вы можете сделать что-то вроде:

let foo = [1,undefined,3]
{ foo.map(e => !!e ? <Object /> : null )}
Gize Каролина Бонилла Мадрасо
источник
8

Отличный вопрос

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

Определите функцию, которая возвращает JSX:

const myExample = () => {
    let myArray = []
    for(let i = 0; i<5;i++) {
        myArray.push(<MyComponent/>)
    }
    return myArray
}

//... in JSX

<tbody>
    {myExample()}
</tbody>
Кристоф Пулио
источник
8

Вы также можете использовать функцию самовызвания:

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

           })()}
        </tbody>
Фба Шад
источник
Использование анонимных функций внутри рендера не считается хорошей практикой в ​​реакции, так как эти функции необходимо пересоздавать или отбрасывать при каждом рендеринге.
Влатко Влахек
@VlatkoVlahek вы ошибаетесь, когда реквизиты функций воссоздаются при каждом цикле рендеринга, что может привести к снижению производительности в больших масштабах. Создание анонимной функции в другом месте не окажет существенного влияния на производительность.
Эмиль Бержерон
1
@EmileBergeron Это было недавно, ха-ха. Я согласен, если это не используется в качестве опоры, нет никакой разницы.
Влатко Влахек