Loop di dalam Bereaksi JSX

1279

Saya mencoba melakukan sesuatu seperti yang berikut di Bereaksi JSX(di mana ObjectRow adalah komponen yang terpisah):

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

Saya menyadari dan mengerti mengapa ini tidak valid JSX, karena JSXpeta berfungsi panggilan. Namun, datang dari tanah templat dan menjadi baru JSX, saya tidak yakin bagaimana saya akan mencapai di atas (menambahkan komponen beberapa kali).

Ben Roberts
sumber
38
Penting untuk dicatat bahwa di JSX Anda memerlukan tag {} di sekitar Sintaks JavaScript Anda. Ini dapat membantu facebook.github.io/react/docs/… .
Isaiah Grey
30
let todos = this.props.todos.map((todo) => {return <h1>{todo.title}</h1>})
OverCoder
@OverCoder mengapa Anda memasukkan seluruh pengembalian ke tag {} itu akan menjadi => return <h1> {todo.title} </h1> bukan?
pravin poudel
1
@ pravinpoudel sebenarnya jawaban itu sudah tua, lebih seperti let todos = this.props.todos.map(t => <h1>{t.title}</h1>):)
OverCoder

Jawaban:

1205

Anggap saja Anda hanya memanggil fungsi JavaScript. Anda tidak dapat menggunakan forloop di mana argumen untuk panggilan fungsi akan:

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

Lihat bagaimana fungsi tbodydilewatkan forsebagai argumen, dan tentu saja itu adalah kesalahan sintaksis.

Tapi Anda bisa membuat array, dan meneruskannya sebagai argumen:

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

Anda pada dasarnya dapat menggunakan struktur yang sama ketika bekerja dengan 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>;

Kebetulan, contoh JavaScript saya hampir persis seperti apa contoh dari JSX berubah menjadi. Bermain-main dengan Babel REPL untuk merasakan bagaimana JSX bekerja.

Sophie Alpert
sumber
3
Mungkin saja kompiler telah berubah, karena contoh ini sepertinya tidak dikompilasi di kompiler jsx , tetapi menggunakan peta seperti pada jawaban FakeRainBrigand di bawah ini tampaknya mengkompilasi dengan benar.
rav
9
Saya bisa menjanjikan bahwa contoh terakhir masih mengkompilasi dengan benar pada kompiler JSX terbaru.
Sophie Alpert
3
Ini bekerja dengan baik. Jawaban FakeRainBrigand berfungsi untuk iterasi array sederhana, tetapi jawaban ini adalah keharusan untuk skenario di mana Anda tidak dapat menggunakan map(mis. Anda tidak memiliki koleksi yang disimpan dalam variabel).
Kelvin
52
Bereaksi perlu memperbarui dom secara efisien, dalam hal ini, orang tua harus menetapkan a keyuntuk setiap childern. REF: facebook.github.io/react/docs/…
qsun
7
Ini adalah contoh yang akan berfungsi, tetapi melewatkan beberapa bit penting seperti keyproperti dan juga gaya kode yang tidak benar-benar digunakan dalam Bereaksi basis kode. Silakan pertimbangkan jawaban ini stackoverflow.com/questions/22876978/loop-inside-react-jsx/… sebagai jawaban yang benar.
okonetchnikov
867

Tidak yakin apakah ini akan berhasil untuk situasi Anda, tetapi seringkali peta adalah jawaban yang baik.

Jika ini kode Anda dengan for loop:

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

Anda bisa menulis seperti ini dengan peta :

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

Sintaks ES6:

<tbody>
    {objects.map((object, i) => <ObjectRow obj={object} key={i} />)}
</tbody>
Perampok
sumber
43
Peta lebih masuk akal jika iteratee adalah array; A for loop sesuai jika itu adalah angka.
Code Whisperer
26
<tbody>{objects.map((o, i) => <ObjectRow obj={o} key={i}/>}</tbody>menggunakan dukungan Reactify's ES6 atau Babel.
Distortum
3
+1. Saya bahkan menggunakan ini dengan ul (daftar unordered). <ul> {objects.map((object:string,i:number)=>{ return <li>{object}</li> })} </ul>menggunakan TypeScript
Roberto C Navarro
5
ini hebat, tetapi Anda tidak dapat memetakan suatu objek .. untuk itu saya akan menggunakanfor..in
Damon
4
Ingatlah bahwa urutan kunci berubah-ubah saat menggunakan Object.keys. Saya menemukan bahwa menyimpan urutan tombol secara terpisah berfungsi dengan baik, dan juga urutan pada objek literal jika perlu. Itu memungkinkan saya untuk menulis kode sepertithis.props.order.map((k)=><ObjectRow key={k} {...this.props.items[k]} />)
tgrrr
443

Jika Anda belum memiliki larik untuk map()menyukai jawaban @ FakeRainBrigand, dan ingin menguraikan ini sehingga tata letak sumber terkait dengan keluaran yang lebih dekat daripada jawaban @ SophieAlpert:

Dengan sintaksis ES2015 (ES6) (fungsi sebar dan panah)

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

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

Re: transpiling dengan Babel, halaman peringatannya mengatakan bahwa Array.fromdiperlukan untuk menyebar, tetapi saat ini ( v5.8.23) yang tampaknya tidak terjadi ketika menyebarkan yang sebenarnya Array. Saya punya masalah dokumentasi yang terbuka untuk mengklarifikasi itu. Tetapi gunakan dengan risiko Anda sendiri atau 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>

Kombinasi teknik dari jawaban lain

Pertahankan tata letak sumber sesuai dengan output, tetapi buat bagian inline lebih kompak:

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

Dengan sintaks & Arraymetode ES2015

Dengan Array.prototype.fillAnda dapat melakukan ini sebagai alternatif untuk menggunakan spread seperti yang diilustrasikan di atas:

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

(Saya pikir Anda benar-benar dapat menghilangkan argumen apa pun fill(), tapi saya tidak 100% tentang itu.) Terima kasih kepada @FakeRainBrigand untuk memperbaiki kesalahan saya dalam versi fill()solusi yang lebih lama (lihat revisi).

key

Dalam semua kasus, keyattr mengurangi peringatan dengan build development, tetapi tidak dapat diakses pada anak. Anda dapat melewati attr tambahan jika Anda ingin indeks tersedia pada anak. Lihat Daftar dan Kunci untuk diskusi.

JMM
sumber
2
Bagaimana dengan yield? Mendorong elemen ke array perantara agak jelek ketika kita memiliki generator. Apakah mereka bekerja
mpen
2
@ Mark Saya tidak tahu generator benar-benar berlaku di sini. Hal utama untuk ini dalam konteks JSX adalah ekspresi yang mengembalikan array. Jadi jika Anda akan menggunakan generator entah bagaimana Anda mungkin akan menyebarkannya, dan itu mungkin akan lebih bertele-tele daripada solusi berbasis ES2015 di sini.
JMM
2
Bagaimana ini lebih verbose? Dan mengapa BEJ tidak menerima iterable, bukan hanya array?
mpen
2
@Ark Itu memang kurang verbose dari (ES5) contoh IIFE yang saya gunakan, tapi itu jauh lebih verbose dari [...Array(x)].map(() => <El />))versi, yang saya pikir paling elegan, dan mengapa saya menampilkannya. Re: pertanyaan kedua, itu poin yang bagus. Tampaknya tidak ada apa-apa tentang JSX yang menghalanginya, jadi itu tergantung apa yang React atau konsumen lain dari BEJ berubah lakukan dengan argumen anak-anak, yang saya tidak bisa mengatakan tanpa melihat sumbernya. Apakah anda tahu Ini pertanyaan yang menarik.
JMM
3
@corysimmons Keren, terima kasih atas informasinya fill(). Saya ingat sekarang bahwa alasan saya ragu-ragu tentang itu adalah pertanyaan tentang bagaimana opsionalitas parameter ditunjukkan dalam spesifikasi ES (harus melihat ke dalam itu kapan-kapan). Koma hanyalah cara untuk menghilangkan elemen array - dalam hal ini yang pertama. Anda dapat melakukannya jika Anda ingin indeks berasal dari 1.. panjang array yang Anda sebarkan daripada 0..panjang-1 dari array spread (karena elemen elided hanya berkontribusi pada panjang array dan tidak t memiliki properti yang sesuai).
JMM
85

Cukup menggunakan metode map Array dengan sintaks ES6:

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

Jangan lupakan keypropertinya.

danielfeelfine
sumber
Saya menambahkan kunci 'Math.random ()' acak alih-alih id itu tidak berfungsi dengan baik ketika setState di dalam anak-anak, Anda tahu mengapa?
Oliver D
82

Menggunakan fungsi peta Array adalah cara yang sangat umum untuk loop melalui array elemen dan membuat komponen sesuai dengan mereka dalam Bereaksi , ini adalah cara yang bagus untuk melakukan loop yang cukup efisien dan rapi untuk melakukan loop Anda di JSX , Ini bukan satu-satunya cara untuk melakukannya, tetapi cara yang disukai.

Juga, jangan lupa memiliki Kunci unik untuk setiap iterasi sebagaimana diperlukan. Fungsi peta membuat indeks unik dari 0 tetapi tidak disarankan menggunakan indeks yang dihasilkan tetapi jika nilai Anda unik atau jika ada kunci unik, Anda dapat menggunakannya:

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

Juga, beberapa baris dari MDN jika Anda tidak terbiasa dengan fungsi peta di Array:

map memanggil fungsi callback yang disediakan satu kali untuk setiap elemen dalam sebuah array, secara berurutan, dan membangun sebuah array baru dari hasilnya. panggilan balik dipanggil hanya untuk indeks array yang telah menetapkan nilai, termasuk yang tidak ditentukan. Itu tidak dipanggil untuk elemen array yang hilang (yaitu, indeks yang belum pernah ditetapkan, yang telah dihapus atau yang tidak pernah diberi nilai).

callback dipanggil dengan tiga argumen: nilai elemen, indeks elemen, dan objek Array yang dilalui.

Jika parameter thisArg disediakan untuk memetakan, parameter ini akan digunakan sebagai callback untuk nilai ini. Jika tidak, nilai yang tidak terdefinisi akan digunakan sebagai nilai ini. Nilai ini pada akhirnya dapat diamati oleh callback ditentukan sesuai dengan aturan biasa untuk menentukan ini dilihat oleh suatu fungsi.

map tidak mengubah array yang dipanggil (walaupun dipanggil kembali, jika dipanggil, mungkin melakukannya).

Alireza
sumber
Array#mapbukan async!
philraj
52

Jika Anda sudah menggunakan lodash, _.timesfungsinya sangat praktis.

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
sumber
1
Array.prototype.map bisa menjadi pilihan bagus di sini jika Anda tidak menyertakan perpustakaan seperti lodash. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… .
Isaiah Grey
1
@IsaiahGrey Hanya jika Anda sudah memiliki array. Terkadang Anda hanya ingin mengulangi beberapa hal.
mpen
1
tentu saja! Lot pendekatan yang berbeda pasti tergantung pada data aktual. Saya menemukan bahwa lebih sering daripada tidak dalam proses pengembangan kami, kami dapat menyesuaikan peta karena bagaimana data jika dimodelkan. Contoh yang bagus menggunakan lodash! Btw, apakah Anda menggunakan sintaks initializer properti untuk mengikat metode Anda ke komponen Anda?
Yesaya Gray
4
@ IsaiahGrey Saya pikir mereka hanya disebut definisi metode
ES6
41

Anda juga dapat mengekstrak di luar blok balik:

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

    return (<tbody>{rows}</tbody>);
}
Brandon Sibeitokgong
sumber
34

Saya tahu ini adalah utas lama, tetapi Anda mungkin ingin checkout React Templates , yang memungkinkan Anda menggunakan templat gaya jsx dalam bereaksi, dengan beberapa arahan (seperti rt-repeat).

Contoh Anda, jika Anda menggunakan templat reaksi, akan menjadi:

<tbody>
     <ObjectRow rt-repeat="obj in objects"/>
</tbody>
Etai
sumber
Mengapa menggunakan pustaka tambahan sementara javascript biasa telah memberikan solusi dengan berbagai macam metode for loop atau Array.prototype.map untuk menyelesaikan masalah? Saya sendiri sudah menggunakan kedua cara javascript biasa dalam proyek saya saat ini yang bekerja dengan baik. Memiliki kebiasaan menggunakan cara javascript biasa jika memungkinkan membantu saya untuk meningkatkan keterampilan saya dalam javascript. Saya hanya menggunakan pustaka tambahan ketika tampaknya sulit untuk menemukan solusi untuk masalah tertentu, seperti routing dengan React-Router.
Lex Soft
27

Ada beberapa cara untuk melakukan ini. JSX akhirnya dikompilasi ke JavaScript, jadi selama Anda menulis JavaScript yang valid, Anda akan baik-baik saja.

Jawaban saya bertujuan untuk menggabungkan semua cara indah yang telah disajikan di sini:

Jika Anda tidak memiliki array objek, cukup jumlah baris:

di dalam returnblok, membuat Arraydan menggunakan Array.prototype.map:

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

di luar returnblok, cukup gunakan JavaScript normal untuk-loop:

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

ekspresi fungsi segera dipanggil:

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

Jika Anda memiliki berbagai objek

di dalam returnblok, .map()setiap objek ke <ObjectRow>komponen:

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

di luar returnblok, cukup gunakan JavaScript normal untuk-loop:

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

ekspresi fungsi segera dipanggil:

render() {
  return (
    <tbody>
      {(() => {
        const rows = [];
        for (let i = 0; i < objectRows.length; i++) {
          rows.push(<ObjectRow key={i} data={objectRows[i]} />);
        }
        return rows;
      })()}
    </tbody>
  );
}
Yangshun Tay
sumber
2
Jawaban bagus: berbagai teknik, semua hanya menggunakan javascript biasa yang menunjukkan kekuatan javascript, berkat berbagai cara melakukan tugas yang serupa.
Lex Soft
24

jika numrows adalah array, dan itu sangat sederhana.

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

Jenis data array dalam Bereaksi lebih baik, array dapat mendukung array baru, dan mendukung filter, mengurangi dll.

lulin
sumber
Ini bukan jawaban yang layak karena tidak menggunakan kunci.
kojow7
21

Ada beberapa jawaban yang menunjuk menggunakan mappernyataan itu. Berikut adalah contoh lengkap menggunakan iterator dalam komponen FeatureList untuk mendaftar komponen Fitur berdasarkan pada struktur data JSON yang disebut fitur .

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

Anda dapat melihat kode FeatureList lengkap di GitHub. The fitur perlengkapan terdaftar di sini .

Manav Sehgal
sumber
Ketika berurusan dengan data JSON, seperti saat mengambil data dari database menggunakan fetch API, saya mengandalkan menggunakan metode Array.prototype.map. Ini adalah cara yang mudah dan terbukti untuk tujuan itu.
Lex Soft
17

Untuk mengulang beberapa kali dan kembali, Anda dapat mencapainya dengan bantuan fromdan map:

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

dimana i = number of times


Jika Anda ingin menetapkan ID kunci unik ke dalam komponen yang diberikan, Anda dapat menggunakan React.Children.toArrayseperti yang diusulkan di dokumentasi Bereaksi

React.Children.toArray

Mengembalikan struktur data buram anak-anak sebagai array datar dengan kunci yang ditetapkan untuk setiap anak. Berguna jika Anda ingin memanipulasi koleksi anak-anak dalam metode render Anda, terutama jika Anda ingin memesan ulang atau mengiris this.props.children sebelum meneruskannya.

catatan:

React.Children.toArray()mengubah kunci untuk melestarikan semantik array bersarang ketika meratakan daftar anak-anak. Yaitu, toArray mem-prefix setiap kunci dalam array yang dikembalikan sehingga setiap elemen di-scoped ke array input yang mengandungnya.

<tbody>
  {
    React.Children.toArray(
      Array.from(Array(i)).map(() => <ObjectRow />)
    )
  }
</tbody>
Astaga
sumber
17

Jika Anda memilih untuk mengkonversi ini dalam kembali () dari render metode, pilihan termudah akan menggunakan peta () metode. Petakan array Anda ke dalam sintaks JSX menggunakan fungsi map (), seperti yang ditunjukkan di bawah ini ( sintaks ES6 digunakan ).


Komponen induk di dalam :

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

Harap perhatikan keyatribut yang ditambahkan ke komponen anak Anda. Jika Anda tidak memberikan atribut kunci, Anda dapat melihat peringatan berikut di konsol Anda.

Peringatan: Setiap anak dalam array atau iterator harus memiliki prop "kunci" yang unik.

Catatan: Satu kesalahan umum yang dilakukan orang adalah menggunakan indexkunci saat iterasi, penggunaan indexelemen sebagai kunci adalah anti-pola dan Anda dapat membaca lebih lanjut tentang hal itu di sini . Singkatnya, jika BUKAN daftar statis tidak pernah digunakan indexsebagai kunci.


Sekarang di komponen ObjectRow , Anda dapat mengakses objek dari propertinya.

Di dalam komponen ObjectRow

const { object } = this.props

atau

const object = this.props.object

Ini akan menjemputmu objek yang kamu lewati dari komponen induk ke variabel objectdi komponen ObjectRow . Sekarang Anda dapat memuntahkan nilai-nilai dalam objek itu sesuai dengan tujuan Anda.


Referensi :

metode map () dalam Javascript

ECMA Script 6 atau ES6

bharadhwaj
sumber
16

katakanlah kami memiliki berbagai item di negara Anda:

[{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>
Jan Franz Palngipang
sumber
Saya pikir Anda mungkin perlu menyingkirkan {} setelah peta (item), yang sepertinya berhasil bagi saya.
Ian
15

ES2015 / Babel kemungkinan menggunakan fungsi generator untuk membuat array JSX:

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

...

<tbody>
    {[...jsxLoop(numrows, i =>
        <ObjectRow key={i}/>
    )]}
</tbody>
David Q Hogan
sumber
15

... Atau Anda juga dapat menyiapkan berbagai objek dan memetakannya ke suatu fungsi untuk mendapatkan hasil yang diinginkan. Saya lebih suka ini, karena ini membantu saya untuk menjaga praktik pengkodean yang baik tanpa logika di dalam kembalinya 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>
  )
}
Rafi Ud Daula Refat
sumber
15

Cukup gunakan .map()untuk mengulang koleksi Anda dan mengembalikan <ObjectRow>item dengan properti dari setiap iterasi.

Dengan asumsi objectsadalah array di suatu tempat ...

<tbody>
  { objects.map((obj, index) => <ObjectRow obj={ obj } key={ index }/> ) }
</tbody>
Joshua Michael Wagoner
sumber
15

ES2015 Array.dari dengan fungsi + tombol peta

Jika tidak ada yang dapat .map()Anda gunakan Array.from()dengan mapfungsi untuk mengulangi elemen:

<tbody>
  {Array.from({ length: 5 }, (value, key) => <ObjectRow key={key} />)}
</tbody>
Lakukan Async
sumber
15

Saya menggunakan ini:

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

PS: jangan pernah lupa kuncinya atau Anda akan memiliki banyak peringatan!

JC
sumber
Atau gunakan indeks array jika item Anda tidak memiliki .Idproperti, sepertiitems.map( (item, index) => <Foo key={index}>{item}</Foo>
kontur
13

Saya cenderung menyukai pendekatan di mana logika pemrograman terjadi di luar nilai kembali render. Ini membantu menjaga apa yang sebenarnya mudah grok.

Jadi saya mungkin akan melakukan sesuatu seperti:

import _ from 'lodash';

...

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

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

Memang ini adalah sejumlah kecil kode yang sebaris mungkin berfungsi dengan baik.

Adam Donahue
sumber
Penggemar besar peta lodash untuk beralih melalui objek. Saya akan cenderung import { map } from 'lodash'jadi Anda tidak mengimpor semua fungsi lodash jika Anda tidak membutuhkannya.
Stretch0
Saat ini kita bahkan tidak memerlukan peta lodash - cukup peta array secara langsung.
Adam Donahue
Ya tetapi Anda tidak dapat mengulangi objek dengan es6 map(), hanya array. Itulah yang saya katakan lodash baik untuk perulangan objek.
Stretch0
Saya pikir Anda berarti objectsdalam daftar hal, kesalahan saya.
Adam Donahue
12

Anda tentu saja dapat menyelesaikannya dengan .map seperti yang disarankan oleh jawaban lain. Jika Anda sudah menggunakan babel, Anda bisa berpikir tentang menggunakan jsx-control-statement. Mereka memerlukan sedikit pengaturan, tapi saya pikir itu layak dalam hal keterbacaan (terutama untuk pengembang non-reaksi). Jika Anda menggunakan linter, ada juga eslint-plugin-jsx-control-statement

Jurgo Boemo
sumber
12

Kode JSX Anda akan dikompilasi menjadi kode JavaScript murni, tag apa pun akan diganti oleh ReactElementobjek. Dalam JavaScript, Anda tidak dapat memanggil fungsi beberapa kali untuk mengumpulkan variabel yang dikembalikan.

Itu ilegal, satu-satunya cara adalah menggunakan array untuk menyimpan fungsi yang dikembalikan variabel.

Atau Anda dapat menggunakan Array.prototype.mapyang tersedia sejak JavaScript ES5 untuk menangani situasi ini.

Mungkin kita dapat menulis kompiler lain untuk membuat ulang sintaks JSX baru untuk mengimplementasikan fungsi pengulangan seperti milik Angularng-repeat .

hlissnake
sumber
12

Ini dapat dilakukan dengan berbagai cara.

  1. Seperti yang disarankan di atas, sebelum returnmenyimpan semua elemen dalam array
  2. Loop di dalam return

    Metode 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>
        )

    Metode 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
sumber
Ya. Dalam proyek saya saat ini, saya menggunakan metode 1, yaitu menggunakan metode Array.prototype, forEach () untuk membuat elemen pilih HTML yang diisi oleh data dari database. Namun, saya akan lebih cenderung menggantinya dengan metode Array.prototype.map (), karena metode peta terlihat lebih kompak (kode kurang).
Lex Soft
10

Inilah solusi sederhana untuk itu.

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

Tidak diperlukan pemetaan dan kode kompleks. Anda hanya perlu mendorong baris ke array dan mengembalikan nilai untuk merendernya.

Javasamurai
sumber
Saat membuat elemen pilih html, teknik serupa ini adalah yang pertama kali muncul di benak saya, Jadi saya menggunakannya, meskipun saya menggunakan metode forEach (). Tetapi ketika saya membaca ulang dokumen Bereaksi tentang topik Daftar dan Kunci, saya menemukan bahwa mereka menggunakan metode map () seperti juga ditunjukkan oleh beberapa jawaban di sini. Ini membuat saya berpikir bahwa itu adalah cara yang disukai. Saya setuju, karena terlihat lebih kompak (kode kurang).
Lex Soft
9

Karena Anda menulis sintaksis Javascript di dalam kode JSX, Anda perlu membungkus Javascript Anda dalam kurung kurawal.

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

Berikut ini contoh dari React doc: 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>
  );
}

sebagai kasus Anda, saya sarankan menulis seperti ini:

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

Harap perhatikan bahwa Kunci sangat penting, karena Bereaksi gunakan Kunci untuk membedakan data dalam larik.

Sinka Lee
sumber
9

Saya menggunakannya seperti

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

Anda dapat melakukan sesuatu seperti:

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

Pertanyaan yang bagus

Apa yang saya lakukan ketika saya ingin menambahkan sejumlah komponen adalah menggunakan fungsi pembantu.

Tentukan fungsi yang mengembalikan JSX:

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

//... in JSX

<tbody>
    {myExample()}
</tbody>
Christophe Pouliot
sumber
8

Anda juga dapat menggunakan fungsi self-invaging:

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

           })()}
        </tbody>
Fba Shad
sumber
Menggunakan fungsi anonim di dalam render tidak dianggap sebagai praktik yang baik dalam bereaksi, karena fungsi-fungsi ini perlu dibuat ulang atau dibuang pada setiap re-render.
Vlatko Vlahek
@VlatkoVlahek Anda salah mengartikannya dengan props fungsi sedang dibuat ulang setiap siklus render, yang dapat menyebabkan kinerja yang lebih buruk dalam skala besar. Membuat fungsi anonim di tempat lain tidak akan memengaruhi kinerja secara signifikan.
Emile Bergeron
1
@ EmileBergeron Beberapa waktu lalu, haha. Saya setuju jika ini tidak digunakan sebagai alat peraga, tidak ada perbedaan.
Vlatko Vlahek