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

880

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

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

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

  • 25
    Важно отметить, что в JSX вам нужны теги {} вокруг вашего синтаксиса JavaScript. Это может помочь facebook.github.io/react/docs/… .
  • 19
    let todos = this.props.todos.map((todo) => {return <h1>{todo.title}</h1>})
Теги:

52 ответа

839
Лучший ответ

Думайте об этом, как будто вы просто вызываете функции 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.

  • 2
    Возможно, компилятор изменился, так как этот пример не компилируется в компиляторе jsx , но использование map, как в ответе FakeRainBrigand ниже, похоже, компилируется правильно.
  • 4
    Я могу пообещать, что последний пример по-прежнему правильно компилируется на последнем компиляторе JSX.
Показать ещё 13 комментариев
713

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

Если это был ваш код с циклом 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>
  • 27
    Карта имеет больше смысла, если итератор является массивом; Цикл for подходит, если это число.
  • 22
    <tbody>{objects.map((o, i) => <ObjectRow obj={o} key={i}/>}</tbody> используя поддержку Reactify ES6 или Babel.
Показать ещё 10 комментариев
334

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

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

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

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

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

Vanilla ES5

Array.apply

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

Inline 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>
  );
}

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

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

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

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

key

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

  • 1
    Как насчет yield ? Вставка элементов в промежуточный массив выглядит некрасиво, когда у нас есть генераторы. Они работают?
  • 1
    @ Марк Я не знаю, что генераторы действительно применимы здесь. Ключевым моментом для этого в контексте JSX является выражение, которое возвращает массив. Поэтому, если вы собираетесь использовать генератор каким-либо образом, вы, вероятно, все равно будете его распространять, и он, вероятно, будет более многословным, чем решения на базе ES2015.
Показать ещё 15 комментариев
60

Просто используя метод map Array с синтаксисом ES6:

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

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

58

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

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

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

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

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

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

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

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

  • 0
    Array#map не асинхронна!
37

Если вы уже используете 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>
        );
    }
}
  • 0
    Array.prototype.map может быть отличным вариантом, если вы не включаете такую библиотеку, как lodash. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… .
  • 0
    @IsaiahGrey Только если у вас уже есть массив. Иногда вы просто хотите повторить вещи несколько раз.
Показать ещё 2 комментария
27

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

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

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

Я знаю, что это старый поток, но вы можете проверить http://wix.github.io/react-templates/, что позволяет использовать шаблоны jsx-стиля в реакции, с несколькими (например, rt-repeat).

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

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

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

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

Тип данных Array в React очень хорош, массив может возвращать новый массив и поддерживать фильтр, уменьшать и т.д.

  • 0
    Это не приличный ответ, так как он не использует ключ.
16

Существует несколько ответов, указывающих на использование оператора 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. Здесь перечислены функции.

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

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

[{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>
  • 0
    Я думаю, что вам может понадобиться избавиться от {} после карты (предмета), которая, кажется, сработала для меня.
12

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

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>
  )
}
11

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

Предполагаемые objects - это массив где-нибудь...

<tbody>
  { objects.map((obj, index) => <ObjectRow obj={ obj } key={ index }/> ) }
</tbody>
11

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

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

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

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

Функция 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>
11

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


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

<tbody> { objectArray.map((object, index) => <ObjectRow key={index} object={object}>) } </tbody>

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

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


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

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

const { object } = this.props

или

const object = this.props.object

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


Ссылки:

метод map() в Javascript

ECMA Script 6 или ES6

9

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

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

<tbody>
  {Array.from({ length: 5 }, (v, k) => <ObjectRow key={k} />)}
</tbody>
9

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

9

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

Поэтому я бы, наверное, сделал что-то вроде:

import _ from 'lodash';

...

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

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

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

  • 0
    Большой поклонник карты lodash для итерации по объектам. Я был бы склонен import { map } from 'lodash' поэтому вы не импортируете все функции lodash, если они вам не нужны.
  • 0
    В наши дни нам даже не нужна карта lodash - просто карта над массивом напрямую.
Показать ещё 2 комментария
9

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

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

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

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

8

Для циклы для нескольких раз и возврата, вы можете достичь его с помощью from и map:

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

где i = number of times

8

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

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

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

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

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

вне return блока, просто используйте обычный JavaScript for-loop:

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 блока, просто используйте обычный JavaScript for-loop:

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>
      {(() => {
        let rows = [];
        for (let i = 0; i < objectRows.length; i++) {
          rows.push(<ObjectRow key={i} data={objectRows[i]} />);
        }
        return rows;
      })()}
    </tbody>
  );
}
  • 1
    Отличные ответы: различные техники, все используют только простой javascript, который демонстрирует мощь javascript, благодаря различным способам выполнения похожих задач.
8

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

  • Как было предложено выше, перед return сохраните все элементы в массиве
  • Цикл внутри 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>
    )
    
  • 0
    Да уж. В моем текущем проекте я использую метод 1, т.е. используя метод Array.prototype, метод forEach () для создания элемента выбора HTML, который заполняется данными из базы данных. Однако я, скорее всего, заменю их методом Array.prototype.map (), так как метод map выглядит более компактным (меньше кода).
7

Я использую его как

<tbody>
{ numrows ? (
   numrows.map(obj => { return <ObjectRow /> }) 
) : null}
</tbody>
6

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

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

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

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

           })()}
        </tbody>
  • 0
    Использование анонимных функций внутри рендера не считается хорошей практикой в реакции, так как эти функции необходимо пересоздавать или отбрасывать при каждом рендеринге.
  • 0
    это не повлияет на производительность в этом примере.
5

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

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

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

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

//... in JSX

<tbody>
    {myExample()}
</tbody>
5

Здесь простое решение.

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

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

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

Даже эта часть кода выполняет ту же работу.

    <tbody>
      {array.map(i => 
        <ObjectRow key={i.id} name={i.name} />
      )}
    </tbody>
4

Ниже приведены возможные решения, которые вы можете выполнить в ответных интермедиах итерирующего массива объектов или простого массива

const rows = [];
const numrows = [{"id" : 01, "name" : "abc"}];
numrows.map((data, i) => {
   rows.push(<ObjectRow key={data.id} name={data.name}/>);
});

<tbody>
    { rows }
</tbody>

ИЛИ ЖЕ

const rows = [];
const numrows = [1,2,3,4,5];
for(let i=1, i <= numrows.length; i++){
   rows.push(<ObjectRow key={numrows[i]} />);
};

<tbody>
    { rows }
</tbody>

Обновить:

еще более лучший подход. Я знаком с недавними днями для итерации массива объектов.map непосредственно в рендеринг с возвратом или без возврата

.map с возвратом

   const numrows = [{"id" : 01, "name" : "abc"}];
 <tbody>
       {numrows.map(data=> {
             return <ObjectRow key={data.id} name={data.name}/>
       })}
</tbody>

.map без возврата

   const numrows = [{"id" : 01, "name" : "abc"}];
 <tbody>
       {numrows.map(data=> (
             <ObjectRow key={data.id} name={data.name}/>
       ))}
</tbody>
4

Вот пример из React doc: https://facebook.github.io/react/docs/jsx-in-depth.html#javascript-expressions-as-children

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 использует Key для различения данных в массиве.

4

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

let foo = [1,undefined,3]
{ foo.map(e => !!e ? <Object /> : null )}
3

для печати значения массива, если у вас нет ключевого значения par, а затем используйте ниже код -

  <div>
       {my_arr.map(item => <div>{item} </div> )}                    
  </div>
3

Проблема в том, что вы не возвращаете элемент jsx. Есть и другие решения для таких случаев, но я дам самый простой: "использовать функцию карты"!

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

Это так просто и красиво, не так ли?

3

Ну, вот иди.

{
 [1, 2, 3, 4, 5, 6].map((value, index) => {
  return <div key={index}>{value}</div>
 })
}

Все, что вам нужно сделать, просто нарисуйте массив и верните все, что вы хотите сделать, и, пожалуйста, не забудьте использовать key в элементе возврата.

3

@jacefarm Если я правильно понял, вы можете использовать этот код:

<tbody>
    { new Array(numrows).fill(<ObjectRow/>) } 
</tbody>

Вы можете использовать этот код:

<tbody>
   { new Array(numrows).fill('').map((item, ind) => <ObjectRow key={ind}/>) } 
</tbody>

И это:

<tbody>
    new Array(numrows).fill(ObjectRow).map((Item, ind) => <Item key={ind}/>)
</tbody>
3

Вы можете использовать IIFE, если вы действительно хотите буквально использовать цикл в JSX.

<tbody>
  {
    (function () {
      const view = [];
      for (let i = 0; i < numrows; i++) {
        view.push(<ObjectRow key={i}/>);
      }
      return view;
    }())
  }
</tbody>
  • 0
    Если вы хотите, чтобы ключевое слово this было равно самому классу, просто преобразуйте функцию в жирную стрелку.
3

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

Вот пример грубого кода, который может помочь:

MyClass extends Component {
    constructor() {
        super(props)
        this.state = { elements: [] }
    }
    render() {
        return (<tbody>{this.state.elements}<tbody>)
    }
    add() {
        /*
         * The line below is a cheap way of adding to an array in the state.
         * 1) Add <tr> to this.state.elements
         * 2) Trigger a lifecycle update.
         */
        this.setState({
            elements: this.state.elements.concat([<tr key={elements.length}><td>Element</td></tr>])
        })
    }
}
2

Я нашел еще одно решение для просмотра карты Render

 <tbody>{this.getcontent()}</tbody>

И отдельная функция

 getcontent() {
const bodyarea = this.state.movies.map(movies => (
  <tr key={movies._id}>
    <td>{movies.title}</td>
    <td>{movies.genre.name}</td>
    <td>{movies.numberInStock}</td>
    <td>{movies.publishDate}</td>
    <td>
      <button
        onClick={this.deletMovie.bind(this, movies._id)}
        className="btn btn-danger"
      >
        Delete
      </button>
    </td>
  </tr>
));
return bodyarea;
}

этот пример легко решает многие проблемы

2

Всякий раз, когда вам нужно поместить какой-либо код JavaScript в свой JSX, вы должны положить {} и поместить код JavaScript в эти скобки. Просто так просто.

Таким образом, вы можете зацикливаться внутри jsx/реагировать.

Сказать:

   <tbody>
    {your piece of code in JavaScript }
  </tbody>

Пример:

   <tbody>
    { items.map( ( item ) > { console.log(item) }) } // items looping using map
  </tbody>
2

loop внутри jsx очень просто попробуйте это.

 {
      this.state.data.map((item,index)=>{
        return(
           <ComponentName key={index} data={item}/>
        );
      })
    }
2

Использование карты в реакции - это лучшие практики для итерации по массиву.

Чтобы предотвратить некоторые ошибки с использованием карты synthax es6, используется так:

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

Здесь вы вызываете компонент, поэтому вам не нужно помещать скобки после стрелки.

Но вы можете сделать это тоже:

{items.map((item, index) => (
<ObjectRow key={index} name={item.name} />
))}

или же:

{items.map((item, index) => {
// here you can log item 
      return (
       <ObjectRow key={index} name={item.name} />
     )
})}

Я говорю это, потому что, если вы положите скобку "{}" после того, как стрелка отреагирует, она не выведет ошибку и отобразит белый список.

2

Если numrows является массивом, так как другие ответы наилучшим образом - это метод map. Если его нет, и вы получаете доступ к нему только из jsx, вы также можете использовать этот метод ES6:

<tbody>
    { 
      [...Array(numrows).fill(0)].map((value,index)=><ObjectRow key={index} />)
    } 
</tbody>
2
return (
        <table>
          <tbody>
          {
            numrows.map((item, index) => {
              <ObjectRow data={item} key={index}>
            })
          }
          </tbody>
        </table>
      );
  • 0
    Хотя этот код может ответить на вопрос, предоставление дополнительного контекста относительно того, как и / или почему он решает проблему, улучшит долгосрочную ценность ответа.
  • 1
    Это сломается. Вам нужно закрыть тег ObjectRow, и вы должны вернуть что-то в обратном вызове вашей карты.
2

Реагирующие элементы - простые JS, поэтому вы можете следовать правилу javascript. Таким образом, вы можете использовать цикл for в javascript следующим образом: -

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

Но действительный и лучший способ - использовать функцию .map. Ниже показано: -

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

Здесь необходимо одно: определить ключ. В противном случае он выдает предупреждение, подобное этому: -

warning.js: 36 Предупреждение: каждый дочерний элемент в массиве или итераторе должен иметь уникальный "ключ". Проверьте метод рендеринга ComponentName. Видеть "link" для получения дополнительной информации.

1

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

Еще одна причина, почему мы идем на.map, но почему бы и нет.foEach, потому что.map возвращает новый массив. В наши дни существуют различные способы создания.map.

Ниже в другой версии использования.map подробно показано, как использовать уникальный ключ и как использовать.map для циклизации элементов jsx

.map без возврата при возврате одного элемента jsx и уникального идентификатора из данных в виде ключевой версии

const {objects} = this.state;

<tbody>
    {objects.map(object => <ObjectRow obj={object} key={object.id} />)}
</tbody>

.map без возврата при возврате нескольких элементов jsx и уникального идентификатора из данных в виде ключевой версии

const {objects} = this.state;

<tbody>
    {objects.map(object => (
       <div key={object.id}>
          <ObjectRow obj={object} />
       </div>
    ))}
</tbody>

.map без возврата при возврате одного элемента jsx и индекса в качестве ключевой версии

const {objects} = this.state;

<tbody>
    {objects.map((object, index) => <ObjectRow obj={object} key={'Key${index}'} />)}
</tbody>

.map без возврата при возврате нескольких элементов jsx и индекса в качестве ключевой версии

const {objects} = this.state;

<tbody>
    {objects.map((object, index) => (
       <div key={'Key${index}'}>
          <ObjectRow obj={object} />
       </div>
    ))}
</tbody>

.map с возвратом при возврате нескольких элементов jsx и индекса в качестве ключевой версии

const {objects} = this.state;

<tbody>
    {objects.map((object, index) => {
       return (
         <div key={'Key${index}'}>
            <ObjectRow obj={object} />
         </div>
       )
    })}
</tbody>

.map с возвратом при возврате нескольких элементов jsx и уникального идентификатора из данных в виде ключевой версии

const {objects} = this.state;

<tbody>
    {objects.map(object => {
       return (
         <div key={object.id}>
            <ObjectRow obj={object} />
         </div>
       )
    })}
</tbody>

Другой способ

render(){
  const {objects} = this.state;
  const objectItems = objects.map(object => {
       return (
         <div key={object.id}>
            <ObjectRow obj={object} />
         </div>
       )
    })
return(
   <div>
     <tbody>
       {objectItems}
     </tbody>
   </div>
 )
}
1

используйте {} вокруг javascript внутри блока JSX, чтобы заставить его правильно выполнить любое действие javascript, которое вы пытаетесь сделать.

<tr>
  <td>
    {data.map((item, index) => {
      {item}
    })}
  </td>
</tr>

Это немного неопределенно, но вы можете менять данные для любого массива. Это даст вам таблицу и таблицу для каждого элемента. Если в каждом узле массива имеется не более одной вещи, вам нужно настроить таргетинг, в частности, на действия:

<td>{item.someProperty}</td>

В этом случае вам захочется окружить его другим td и упорядочить предыдущий пример по-другому.

1

Вам нужно писать в JSX

<tbody>
    { 
    objects.map((object, i) => (
        <ObjectRow obj={object} key={i} />
    ));
    }
</tbody>
0
<tbody>
    {objects.map((object) => <ObjectRow obj={object} key={object.id} />)}
</tbody>
0
import React, { Component } from "react";
import ReactDOM from "react-dom";

const numrows = 5;

class Example extends React.Component {
  handle = () => {
    return numrows.map(() => <div>dded</div>);
  };

  render() {
    return <div>{this.handle}</div>;
  }
}

ReactDOM.render(<Example />, document.getElementById("View"));
0

Чтобы обеспечить более прямое решение, если вы хотите использовать определенный счетчик строк, который хранится как Integer -value. С помощью typedArrays мы могли бы достичь желаемого решения следующим образом.

// Let create typedArray with length of 'numrows'-value
const typedArray = new Int8Array(numrows); // typedArray.length is now 2
const rows = []; // Prepare rows-array
for (let arrKey in typedArray) { // Iterate keys of typedArray
  rows.push(<ObjectRow key={arrKey} />); // Push to an rows-array
}
// Return rows
return <tbody>{rows}</tbody>; 
-2
import React, { Component } from 'react'
import ObjectRow from "./test

export default class Index extends Component {

showDummy=()=>{
    return numrows.map(each=><ObjectRow/>)
}

  render() {
     return (
      <div>
       {this.showDummy()}
      </div>
    )
  }
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню