1688

React JSX で次のようなことをしようとしています (ObjectRow は別のコンポーネントです)。

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

JSXは関数呼び出しにマップされるため、これが有効なJSXではない理由を理解しています。ただし、テンプレートの土地から来て、JSX を初めて使用するので、上記をどのように達成するか (コンポーネントを複数回追加する) がわかりません。

4

76 に答える 76

1550

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 are adding 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 がどのように機能するかを感じてください。

于 2014-04-05T05:39:46.420 に答える
580

@FakeRainBrigand の回答を気に入る配列をまだ持っておらずmap()、これをインライン化したい場合は、ソース レイアウトが @SophieAlpert の回答よりも近い出力に対応するようにします。

ES2015 (ES6) 構文 (スプレッド関数とアロー関数) を使用

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

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

Re: Babel でトランスパイルすると、その警告ページにはArray.from、拡散には必須と記載されていますが、現在 ( v5.8.23) 実際の を拡散する場合はそうではないようですArray。それを明確にするために、ドキュメントの問題を開いています。ただし、自己責任またはポリフィルで使用してください。

バニラ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>
  );
}

ES2015 の構文とArrayメソッドを使用

上記のようにスプレッドを使用する代わりに、これArray.prototype.fillを行うことができます。

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

(実際には の引数を省略できると思いますがfill()、100%ではありません。)ソリューションの以前のバージョンでの私の間違いを修正してくれた@FakeRainBrigandに感謝しますfill()(リビジョンを参照)。

key

いずれの場合も、keyattr は開発ビルドの警告を緩和しますが、子ではアクセスできません。子で使用可能なインデックスが必要な場合は、追加の attr を渡すことができます。議論については、リストとキーを参照してください。

于 2015-04-14T14:08:48.323 に答える
118

ES6 構文でmap Arrayメソッドを使用するだけです。

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

keyプロパティを忘れないでください。

于 2016-10-30T04:35:33.107 に答える
78

を既にお使い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}>repeated 3 times</li>
          ))}
        </ol>
      </div>
    );
  }
}
于 2015-10-05T05:35:24.137 に答える
52

return ブロックの外側に抽出することもできます。

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

    return (<tbody>{rows}</tbody>);
}
于 2016-01-04T05:53:11.687 に答える
44

React Templatesをチェックアウトすると、React で JSX スタイルのテンプレートを使用できるようになり、いくつかのディレクティブ (rt-repeat など) が追加されます。

反応テンプレートを使用した場合の例は次のようになります。

<tbody>
     <ObjectRow rt-repeat="obj in objects"/>
</tbody>
于 2015-02-02T19:35:02.017 に答える
34

これをrenderメソッドのreturn()内で変換することを選択した場合、最も簡単なオプションはmap( )メソッドを使用することです。以下に示すように、map() 関数を使用して、配列を JSX 構文にマップします ( ES6 構文が使用されます)。


親コンポーネント内:

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

key属性が子コンポーネントに追加されることに注意してください。キー属性を指定しなかった場合は、コンソールに次の警告が表示されます。

警告: 配列または反復子の各子には、一意の「キー」プロパティが必要です。

注:よくある間違いの 1 つはindex、反復時に をキーとして使用することです。要素をキーとして使用indexすることはアンチパターンです。詳細については、こちらを参照してください。つまり、静的リストでない場合は、決してキーとして使用indexないでください。


ObjectRowコンポーネントで、そのプロパティからオブジェクトにアクセスできます。

ObjectRow コンポーネントの内部

const { object } = this.props

または

const object = this.props.object

これにより、親コンポーネントからObjectRowobjectコンポーネントの変数に渡したオブジェクトが取得されます。これで、目的に応じてそのオブジェクトの値を吐き出すことができます。


参考文献:

JavaScript の map() メソッド

ECMAScript 6 または ES6

于 2016-11-21T09:46:05.863 に答える
34

numrowsが配列の場合は、非常に単純です。

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

React の配列データ型ははるかに優れています。配列は新しい配列をサポートし、フィルター、削減などをサポートできます。

于 2017-01-11T09:49:45.293 に答える
28

あなたの状態にアイテムの配列があるとしましょう:

[{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>
于 2016-08-20T00:15:36.760 に答える
25

ECMAScript 2015 / Babelの可能性として、ジェネレーター関数を使用して JSX の配列を作成しています。

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

...

<tbody>
    {[...jsxLoop(numrows, i =>
        <ObjectRow key={i}/>
    )]}
</tbody>
于 2016-12-28T15:47:09.753 に答える
19

...または、オブジェクトの配列を準備し、それを関数にマップして、目的の出力を得ることもできます。render のリターン内にロジックを持たないコーディングの優れたプラクティスを維持するのに役立つため、私はこれを好みます。

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>
  )
}
于 2016-05-21T18:39:42.830 に答える
15

私は、プログラミング ロジックが の戻り値の外部で発生するアプローチを好む傾向がありますrender。これにより、実際にレンダリングされたものを理解するのが容易になります。

だから私はおそらく次のようなことをするでしょう:

import _ from 'lodash';

...

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

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

確かに、これは非常に少量のコードであるため、インライン化すると問題なく動作する可能性があります。

于 2016-04-01T01:45:27.640 に答える
15

もちろん、他の回答で示唆されているように、.map で解決できます。すでにBabelを使用している場合は、 jsx-control-statements の使用を検討できます。

少し設定が必要ですが、読みやすさの点では価値があると思います (特に非 React 開発者にとって)。リンターを使用する場合は、eslint-plugin-jsx-control-statementsもあります。

于 2016-09-26T09:26:20.700 に答える
14

JSX コードは純粋な JavaScript コードにコンパイルされ、すべてのタグがReactElementオブジェクトに置き換えられます。JavaScript では、返された変数を収集するために関数を複数回呼び出すことはできません。

これは違法です。唯一の方法は、関数が返す変数を格納するために配列を使用することです。

または、JavaScript ES5 以降Array.prototype.mapで利用可能な which を使用して、この状況を処理することもできます。

おそらく、Angular のng-repeat.

于 2015-06-26T09:24:22.180 に答える
11

JSX コード内に JavaScript 構文を記述しているため、JavaScript コードを中かっこで囲む必要があります。

row = () => {
   var rows = [];
   for (let i = 0; i<numrows; i++) {
       rows.push(<ObjectRow/>);
   }
   return rows;
}
<tbody>
{this.row()}
</tbody>
于 2017-01-21T14:18:45.337 に答える
10

自己呼び出し関数を使用することもできます。

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

           })()}
        </tbody>
于 2017-09-21T18:02:10.577 に答える
8

次のようなことができます:

let foo = [1,undefined,3]
{ foo.map(e => !!e ? <Object /> : null )}
于 2017-05-02T01:59:32.493 に答える
8

Array.fromが最善の方法です。ある程度の長さのJSXの配列を作成したい場合。

function App() {
  return (
    <tbody>
      {Array.from({ length: 10 }, (_, key) => (
        <ObjectRow {...{ key }} />
      ))}
    </tbody>
  );
}

上記の例は、配列がない場合の例です。したがって、配列がある場合は、次のように JSX でマップする必要があります。

function App() {
  return (
    <tbody>
      {list.map((item, key) => (
        <ObjectRow {...{ key }} />
      ))}
    </tbody>
  );
}
于 2020-09-10T10:50:27.283 に答える
8

JSX 内のループは非常に単純です。これを試して:

return this.state.data.map((item, index) => (
  <ComponentName key={index} data={item} />
));
于 2018-05-20T08:52:38.023 に答える
5

JSX 内で文字通りforループを使用したい場合は、IIFEを使用できます。

<tbody>
  {
    (function () {
      const view = [];
      for (let i = 0; i < numrows; i++) {
        view.push(<ObjectRow key={i}/>);
      }
      return view;
    }())
  }
</tbody>
于 2017-08-07T09:43:47.250 に答える
4

以下のような新しいコンポーネントを作成できます。

ObjectRow次のようにキーとデータをコンポーネントに渡します。

export const ObjectRow = ({key,data}) => {
    return (
      <div>
          ...
      </div>
    );
}

ObjectRowListデータのコンテナーのように機能する新しいコンポーネントを作成します。

export const ObjectRowList = (objectRows) => {
    return (
      <tbody>
        {objectRows.map((row, index) => (
          <ObjectRow key={index} data={row} />
        ))}
      </tbody>
    );
}
于 2019-08-07T11:49:15.403 に答える
2

If you are used to Angular and want a more React-like approach:

Try using this simple component with auto hashing and optional trackBy similar to Angular's.

Usage:

<For items={items}>
    {item => <div>item</div>}
</For>

Custom key/trackBy:

<For items={items} trackBy={'name'}>
    {item => <div>item</div>}
</For>

Definition:

export default class For<T> extends Component<{ items: T[], trackBy?: keyof T, children: (item: T) => React.ReactElement }, {}> {
    render() {
        return (
            <Fragment>
                {this.props.items.map((item: any, index) => <Fragment key={this.props.trackBy ?? item.id ?? index}>{this.props.children(item)}</Fragment>)}
            </Fragment>
        );
    }
}

React Dev Tools:

Enter image description here

于 2021-01-18T23:26:10.293 に答える
1

簡単な方法

numrows を状態にして、 forループの代わりにmap()を使用できます。

{this.state.numrows.map((numrows , index) => {
      return (
        <ObjectRow
          key={index}
        />
于 2019-11-06T07:49:01.150 に答える