จะส่งคืน JSX หลายบรรทัดในคำสั่ง return อื่นใน React ได้อย่างไร


101

สายเดี่ยวใช้งานได้ดี

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

ไม่ใช่สำหรับหลายบรรทัด

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

ขอบคุณ.


1
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับปัญหานี้: github.com/facebook/react/issues/2127
plus-

ไม่return ("asdf" "asdf");ต้องการreturn ["asdf", "asdf"];
neaumusic

คำตอบ:


150

ลองคิดว่าแท็กเป็นการเรียกใช้ฟังก์ชัน (ดูเอกสาร ) จากนั้นคนแรกจะกลายเป็น:

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

และอันที่สอง:

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

ตอนนี้ควรชัดเจนแล้วว่าตัวอย่างข้อมูลที่สองไม่สมเหตุสมผลจริงๆ (คุณไม่สามารถคืนค่ามากกว่าหนึ่งค่าใน JS) คุณต้องรวมไว้ในองค์ประกอบอื่น (ส่วนใหญ่จะเป็นสิ่งที่คุณต้องการวิธีนั้นคุณสามารถระบุkeyคุณสมบัติที่ถูกต้องได้) หรือคุณสามารถใช้สิ่งนี้

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

ด้วยน้ำตาล JSX:

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

คุณไม่จำเป็นต้องแบนอาร์เรย์ผลลัพธ์ React จะทำเพื่อคุณ ดูต่อไปนี้ซอhttp://jsfiddle.net/mEB2V/1/ อีกครั้ง: การรวมทั้งสององค์ประกอบลงใน div / section มักจะดีกว่าในระยะยาว


4
ใช่บันทึกไว้อย่างชัดเจนfacebook.github.io/react/tips/…
Shawn

1
การใช้ return ([... ]) โดยไม่มีบิตแฟล็ตทำให้ฉันได้มาร์กอัปตรงตามที่ฉันต้องการแม้ว่าอาร์เรย์ที่ส่งคืนจะต้องไม่แฟบ แต่ในกรณีเฉพาะของฉันมันจะไม่มีผลกับผลลัพธ์สุดท้าย หรือว่า?
Shawn

ขอบคุณ! TIL! การอัปเดตคำตอบของฉันเพื่อรวมลิงก์ไปยัง JSFiddle ที่แสดงว่าการแบนเป็นทางเลือก จะรวมลิงค์ไปยังเอกสาร React ด้วย
Jan Olaf Krems

13
สิ่งนี้ไม่ได้ผลอีกต่อไป (ณ 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 ก็ปรับเพื่อกลับอาร์เรย์เป็นส่วนหนึ่งของ<div>{ this.props.foos.map(function() { return <Foo /> }) }</div>การแสดงผลส่วนประกอบเช่น แต่renderฟังก์ชันของคอมโพเนนต์ไม่สามารถส่งคืนอาร์เรย์นั้นได้โดยไม่ต้องห่อหุ้มเช่นใน div
Henrik N

35

ดูเหมือนว่าคำตอบเก่าเกี่ยวกับการส่งคืนอาร์เรย์จะใช้ไม่ได้อีกต่อไป (อาจจะเป็นเพราะ React ~ 0.9 ตามที่ @ dogmatic69 เขียนไว้ในความคิดเห็น )

เอกสารบอกว่าคุณต้องส่งคืนโหนดเดียว:

จำนวนโหนดราก JSX สูงสุด

ขณะนี้ในการเรนเดอร์ของคอมโพเนนต์คุณสามารถส่งคืนโหนดได้เพียงโหนดเดียว หากคุณมีรายการ div ที่จะส่งคืนคุณต้องรวมส่วนประกอบของคุณไว้ใน div, span หรือส่วนประกอบอื่น ๆ

อย่าลืมว่า JSX คอมไพล์เป็น JS ปกติ การส่งคืนฟังก์ชันสองฟังก์ชันไม่ได้ทำให้เกิดความรู้สึกทางวากยสัมพันธ์ ในทำนองเดียวกันอย่าใส่ลูกมากกว่าหนึ่งคนใน ternary

ในหลาย ๆ กรณีคุณสามารถห่อสิ่งของเป็น<div>ไฟล์<span>.

ในกรณีของฉันฉันต้องการส่งคืนหลาย<tr>ตัว ฉันห่อไว้ใน<tbody>ตาราง - อนุญาตให้มีหลายร่าง

แก้ไข: ในการตอบสนอง 16.0 การส่งคืนอาร์เรย์จะได้รับอนุญาตอีกครั้งตราบเท่าที่แต่ละองค์ประกอบมีkey: https://facebook.github.io/react/blog/2017/09/26/react-v16.0.html # new-render-return-types-fragments-and-strings

แก้ไข: React 16.2 ช่วยให้คุณสามารถล้อมรอบรายการองค์ประกอบที่มี<Fragment>…</Fragment>หรือแม้กระทั่ง<>…</>หากคุณต้องการให้อาร์เรย์: https://blog.jmes.tech/react-fragment-and-semantic-html/


3
คุณสามารถทำอะไรถ้าคุณต้องการที่จะกลับมาหลาย<li>? สมมติว่าฉันไม่สามารถห่อทั้งหมดได้<ul>
Banjocat

@ Banjocat ฉันกลัวว่าฉันไม่รู้: / คุณได้รับอนุญาตให้ซ้อนรายการดังนั้นคุณสามารถส่งคืนบางสิ่งเช่น<li><ul><li>one</li><li>two</li></ul></li>ถ้ามันใช้ได้กับสถานการณ์ของคุณ หรือ: div การตัดไม่ถูกต้องอย่างเคร่งครัด แต่อาจแสดงผลได้ดีในเบราว์เซอร์ที่เกี่ยวข้องทั้งหมด? หากคุณลองโปรดแจ้งให้เราทราบ
Henrik N

1
@ Banjocat ... ฉันอยากรู้คำตอบที่ดีกว่าสำหรับคำถามของคุณ บางทีคุณควรตั้งเป็นคำถาม stackoverflow ปกติและดูว่าคุณได้รับคำตอบอื่นหรือไม่
user1175849

@ user1175849 บางทีคุณอาจจะโพสต์คำถามนั้นก็ได้ :)
Henrik N

1
@HenrikN Fwiw การตัด "ส่วนย่อย" liในspanหรือdivไม่ได้ผลสำหรับฉัน div นั้นทำให้การเรนเดอร์พังอย่างมากและอย่างน้อยในกรณีการใช้งานของฉันสแปนนั้นทำให้ CSS ยุ่ง 2 ¢: การพยายามส่งคืนชุดย่อยหลายชุดliเป็นกลิ่นรหัส เราใช้ a ulเป็นเมนูแบบเลื่อนลงและตอนแรกฉันต้องการให้หลาย ๆ องค์ประกอบคืนค่า "ส่วน" ของlis ในท้ายที่สุดแล้วการใส่รหัสเมนูทั้งหมดลงในส่วนประกอบเดียวที่ "ยึด" ได้ดีกว่าที่จะใส่ulรองเท้าliจากหลายแหล่ง ฉันคิดว่ามันทำให้รูปแบบจิตใจสำหรับ UI สะอาดขึ้นเล็กน้อย
ruffin

13

จาก React v16.0.0เป็นต้นไปคุณสามารถส่งคืนองค์ประกอบหลายรายการได้โดยการรวมไว้ในไฟล์Array

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

นอกจากนี้จากReact v16.2.0ยังมีReact Fragmentsการนำเสนอคุณลักษณะใหม่ที่เรียกว่าซึ่งคุณสามารถใช้เพื่อรวมหลายองค์ประกอบได้

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

ตามเอกสาร:

รูปแบบทั่วไปใน React มีไว้สำหรับคอมโพเนนต์ที่จะส่งคืนหลายองค์ประกอบ แฟรกเมนต์ช่วยให้คุณจัดกลุ่มรายชื่อเด็กโดยไม่ต้องเพิ่มโหนดเพิ่มเติมใน DOM

แฟรกเมนต์ที่ประกาศด้วยไวยากรณ์ที่ชัดเจนอาจมีคีย์ กรณีการใช้งานสำหรับสิ่งนี้คือการแม็พคอลเลกชันกับอาร์เรย์ของแฟรกเมนต์ - ตัวอย่างเช่นเพื่อสร้างรายการคำอธิบาย:

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

คีย์เป็นแอตทริบิวต์เดียวที่สามารถส่งผ่านไปยัง Fragment ได้ ในอนาคตเราอาจเพิ่มการสนับสนุนสำหรับแอตทริบิวต์เพิ่มเติมเช่นตัวจัดการเหตุการณ์


7

นอกจากนี้คุณอาจต้องการส่งคืนรายการหลายรายการในฟังก์ชันตัวช่วยบางอย่างภายในองค์ประกอบการตอบสนอง เพียงส่งคืนอาร์เรย์ของโหนด html ที่มีkeyแอตทริบิวต์:

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>,
    ]
  }
}

3

อัปเดตแล้ว

ใช้ React Fragment เป็นเรื่องง่าย ลิงก์ไปยังเอกสารส่วนย่อย

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

คำตอบเก่า - ล้าสมัย

ด้วยการตอบสนอง> 16 คุณใช้งานสามารถตอบสนองคอมโพสิต

import { Composite } from 'react-composite';

// ...

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

แน่นอนว่าต้องติดตั้ง react-composite

npm install react-composite --save

2

คุณสามารถใช้createFragmentที่นี่

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

(ใช้ไวยากรณ์ ES6 และ JSX ที่นี่)

คุณต้องเพิ่มreact-addons-create-fragmentแพ็คเกจก่อน:

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

ข้อได้เปรียบเหนือโซลูชันของ Jan Olaf Krems: ตอบสนองไม่บ่นเกี่ยวกับสิ่งที่หายไป key


แก้ไขฉันถ้าฉันผิด แต่คุณสามารถเพิ่มคีย์ด้วยตนเองได้ โดยใช้ตัวอย่างของ jan: รายการอาร์เรย์แรกได้รับเช่น <h3 key = {i}> </h3> และรายการอาร์เรย์ที่สองแตกต่างกันเล็กน้อยเช่น <p> key = {i + '-foo'}> </p>
nerdess

1

มันง่ายมากโดย React fragment <></>และReact.Fragment:

return (
    <>
      {[1, 2, 3].map(
        (n, index): ReactElement => (
          <React.Fragment key={index}>
            <h3>Item {n}</h3>
            <p>Description {n}</p>
          </React.Fragment>
        ),
      )}
    </>
  );
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.