Bagaimana cara mengembalikan beberapa baris JSX dalam pernyataan pengembalian lain di React?

100

Garis tunggal berfungsi dengan baik

render: function () {
  return (
    {[1,2,3].map(function (n) {
      return <p>{n}</p>
    }}
  );
}

bukan untuk beberapa baris

render: function () {
  return (
    {[1,2,3].map(function (n) {
      return (
        <h3>Item {n}</h3>
        <p>Description {n}</p>
      )
    }}
  );
}

Terima kasih.

Shawn
sumber
1
Untuk info lebih lanjut tentang masalah khusus ini: github.com/facebook/react/issues/2127
plus-
tidak return ("asdf" "asdf");Anda inginkanreturn ["asdf", "asdf"];
neaumusic

Jawaban:

149

Cobalah untuk menganggap tag sebagai panggilan fungsi (lihat dokumen ). Kemudian yang pertama menjadi:

{[1,2,3].map(function (n) {
  return React.DOM.p(...);
})}

Dan yang kedua:

{[1,2,3].map(function (n) {
  return (
    React.DOM.h3(...)
    React.DOM.p(...)
  )
})}

Sekarang seharusnya sudah jelas bahwa cuplikan kedua tidak benar-benar masuk akal (Anda tidak dapat mengembalikan lebih dari satu nilai di JS). Anda harus membungkusnya dengan elemen lain (kemungkinan besar apa yang Anda inginkan, dengan begitu Anda juga dapat memberikan keyproperti yang valid ), atau Anda dapat menggunakan sesuatu seperti ini:

{[1,2,3].map(function (n) {
  return ([
    React.DOM.h3(...),
    React.DOM.p(...)
  ]);
})}

Dengan gula JSX:

{[1,2,3].map(function (n) {
  return ([
    <h3></h3>, // note the comma
    <p></p>
  ]);
})}

Anda tidak perlu meratakan array yang dihasilkan, React akan melakukannya untuk Anda. Lihat biola berikut http://jsfiddle.net/mEB2V/1/ . Sekali lagi: Membungkus kedua elemen menjadi div / bagian kemungkinan besar akan lebih baik untuk jangka panjang.

Jan Olaf Krems
sumber
4
Ya, sebenarnya facebook.github.io/react/tips/…
Shawn
1
Menggunakan return ([...]) tanpa bit flatten memberi saya markup persis seperti yang saya inginkan, meskipun array yang dikembalikan tidak boleh rata tetapi dalam kasus khusus saya itu tidak mempengaruhi hasil akhir. Atau itu?
Shawn
Terima kasih! TIL! Memperbarui jawaban saya untuk menyertakan tautan ke JSFiddle yang menunjukkan bahwa rata adalah opsional. Juga akan menyertakan link ke dokumen React.
Jan Olaf Krems
13
Ini bekerja tidak lagi (per 0.9ish)Uncaught Error: Invariant Violation: Product.render(): A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object.
dogmatic69
2
@TimFletcher Tidak apa-apa mengembalikan array sebagai bagian dari rendering komponen, misalnya <div>{ this.props.foos.map(function() { return <Foo /> }) }</div>. Tetapi renderfungsi komponen tidak dapat mengembalikan larik itu tanpa membungkusnya, misalnya dalam sebuah div.
Henrik N
35

Sepertinya jawaban lama tentang mengembalikan array tidak lagi berlaku (mungkin sejak React ~ 0.9, seperti yang ditulis @ dogmatic69 dalam komentar ).

Dokumen mengatakan Anda perlu mengembalikan satu node:

Jumlah Maksimum Root Node JSX

Saat ini, dalam render komponen, Anda hanya dapat mengembalikan satu node; Jika Anda memiliki, katakanlah, daftar div untuk dikembalikan, Anda harus menggabungkan komponen Anda dalam div, span, atau komponen lainnya.

Jangan lupa bahwa JSX dikompilasi menjadi JS biasa; mengembalikan dua fungsi tidak benar-benar masuk akal secara sintaksis. Demikian pula, jangan letakkan lebih dari satu anak di terner.

Dalam banyak kasus, Anda cukup membungkus sesuatu dalam a <div>atau a <span>.

Dalam kasus saya, saya ingin mengembalikan beberapa <tr>s. Saya membungkusnya dalam sebuah <tbody>- tabel diperbolehkan untuk memiliki banyak badan.

EDIT: Pada React 16.0, mengembalikan array tampaknya diizinkan lagi, selama setiap elemen memiliki key: https://facebook.github.io/react/blog/2017/09/26/react-v16.0.html # new-render-return-types-fragments-and-strings

EDIT: React 16.2 memungkinkan Anda mengelilingi daftar elemen dengan <Fragment>…</Fragment>atau bahkan <>…</>, jika Anda lebih suka itu daripada array: https://blog.jmes.tech/react-fragment-and-semantic-html/

Henrik N
sumber
3
Apa yang dapat Anda lakukan jika ingin mengembalikan lebih dari satu <li>? Dengan asumsi bahwa saya tidak bisa begitu saja membungkus semuanya<ul>
Banjocat
@Banjocat Saya khawatir saya tidak tahu: / Anda diizinkan untuk menyusun daftar bersarang , jadi Anda dapat mengembalikan sesuatu seperti <li><ul><li>one</li><li>two</li></ul></li>jika itu berhasil dalam situasi Anda. Atau: div pembungkus tidak sepenuhnya valid tetapi mungkin berfungsi dengan baik di semua browser yang relevan? Jika Anda mencobanya, beri tahu kami.
Henrik N
1
@Banjocat ... Saya ingin tahu jawaban yang lebih baik untuk pertanyaan Anda. Mungkin Anda harus mengajukannya sebagai pertanyaan stackoverflow biasa dan melihat apakah Anda mendapatkan jawaban yang berbeda.
pengguna1175849
@ user1175849 Mungkin Anda bisa memposting pertanyaan itu kemudian :)
Henrik N
1
@HenrikN FWIW, membungkus "bagian" dari lidalam spanatau divtidak bekerja dengan baik bagi saya. Div secara serius merusak rendering, dan, setidaknya dalam kasus penggunaan saya, span mengacaukan CSS. 2 ¢: Mencoba mengembalikan beberapa himpunan bagian dari lis adalah kode bau. Kami menggunakan ulsebagai semacam menu tarik-turun, dan saya awalnya ingin banyak komponen mengembalikan "bagian" dari lis. Pada akhirnya, lebih baik meletakkan semua kode menu ke dalam satu komponen "berlabuh" uldaripada memasukkannya lidari berbagai sumber. Saya pikir itu juga membuat model mental untuk UI sedikit lebih bersih.
ruffin
13

Dari React v16.0.0 dan seterusnya, dimungkinkan untuk mengembalikan banyak elemen dengan membungkusnya di dalam fileArray

render() {
  return (
    {[1,2,3].map(function (n) {
      return [
        <h3>Item {n}</h3>.
        <p>Description {n}</p>
      ]
    }}
  );
}

Juga dari React v16.2.0 , fitur baru bernama React Fragmentsdiperkenalkan yang dapat Anda gunakan untuk membungkus banyak elemen

render() {
  return (
    {[1,2,3].map(function (n, index) {
      return (
        <React.Fragment key={index}>
            <h3>Item {n}</h3>
            <p>Description {n}</p>
        </React.Fragment>
      )
    }}
  );
}

Sesuai dokumentasi:

Pola umum di React adalah komponen mengembalikan banyak elemen. Fragmen memungkinkan Anda mengelompokkan daftar anak-anak tanpa menambahkan node tambahan ke DOM.

Fragmen yang dideklarasikan dengan sintaks eksplisit mungkin memiliki kunci. Contoh penggunaan untuk ini adalah memetakan koleksi ke array fragmen - misalnya, untuk membuat daftar deskripsi:

function Glossary(props) {
  return (
    <dl>
      {props.items.map(item => (
        // Without the `key`, React will fire a key warning
        <React.Fragment key={item.id}>
          <dt>{item.term}</dt>
          <dd>{item.description}</dd>
        </React.Fragment>
      ))}
    </dl>
  );
}

key adalah satu-satunya atribut yang dapat diteruskan ke Fragment. Di masa mendatang, kami mungkin menambahkan dukungan untuk atribut tambahan, seperti pengendali event.

Shubham Khatri
sumber
7

Juga, Anda mungkin ingin mengembalikan beberapa item daftar di beberapa fungsi pembantu di dalam komponen React. Cukup kembalikan array node html dengan keyatribut:

import React, { Component } from 'react'

class YourComponent extends Component {
  // ...

  render() {
    return (
      <ul>
        {this.renderListItems()}
      </ul>
    )
  }      

  renderListItems() {
    return [
      <li key={1}><a href="#">Link1</a></li>,
      <li key={2}><a href="#">Link2</a></li>,
      <li key={3} className="active">Active item</li>,
    ]
  }
}
Dmitriy
sumber
2

Anda dapat menggunakan di createFragmentsini.

https://facebook.github.io/react/docs/create-fragment.html

import createFragment from 'react-addons-create-fragment';
...
{[1,2,3].map((n) => createFragment({
    h: <h3>...</h3>,
    p: <p>...</p>
  })
)}

(menggunakan sintaks ES6 dan JSX di sini)

Anda harus menambahkan react-addons-create-fragmentpaket terlebih dahulu:

npm install --save react-addons-create-fragment

Keuntungan dari solusi Jan Olaf Krems: bereaksi tidak mengeluh tentang yang hilang key

sylvain
sumber
perbaiki saya jika saya salah tetapi Anda cukup menambahkan kunci secara manual. menggunakan contoh jan: item larik pertama mendapatkan mis. <h3 key = {i}> </h3> dan item larik kedua sth sedikit berbeda seperti <p> ​​key = {i + '-foo'}> </p>
nerdess
2

Diperbarui

Gunakan React Fragment. Itu mudah. Tautan ke dokumentasi fragmen.

render() {
  return (
    <>
    {[1,2,3].map((value) => <div>{value}</div>)}
    </>
  );
}

Jawaban lama - usang

Dengan React> 16 Anda dapat menggunakan react-composite .

import { Composite } from 'react-composite';

// ...

{[1,2,3].map((n) => (
  <Composite>
    <h2>Title {n}</h2>
    <p>Description {n}</p>
  </Composite>
))};

Tentu saja, react-composite harus dipasang.

npm install react-composite --save
Bapak Br
sumber
0

Ini sederhana dengan fragmen React <></>dan React.Fragment:

return (
    <>
      {[1, 2, 3].map(
        (n, index): ReactElement => (
          <React.Fragment key={index}>
            <h3>Item {n}</h3>
            <p>Description {n}</p>
          </React.Fragment>
        ),
      )}
    </>
  );
Masih Jahangiri
sumber