วนซ้ำภายใน React JSX


1278

ฉันพยายามทำสิ่งต่อไปนี้ใน React JSX(โดยที่ ObjectRow เป็นส่วนประกอบแยกต่างหาก):

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

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


38
สิ่งสำคัญคือให้สังเกตว่าใน JSX คุณต้องมีแท็ก {} ล้อมรอบไวยากรณ์ JavaScript ของคุณ นี้อาจช่วยให้facebook.github.io/react/docs/...
Isaiah Gray

30
let todos = this.props.todos.map((todo) => {return <h1>{todo.title}</h1>})
OverCoder


@OverCoder ทำไมคุณต้องใส่ผลตอบแทนทั้งหมดลงในแท็ก {} มันจะเป็น => return <h1> {todo.title} </h1> ใช่ไหม
pravin poudel

1
@pravinpoudel จริงว่าคำตอบคืออายุมากขึ้นเช่นlet todos = this.props.todos.map(t => <h1>{t.title}</h1>):)
OverCoder

คำตอบ:


1205

ลองคิดดูว่าคุณแค่เรียกใช้ฟังก์ชัน 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 ทำงานอย่างไร


3
อาจเป็นไปได้ว่าคอมไพเลอร์มีการเปลี่ยนแปลงเนื่องจากตัวอย่างนี้ดูเหมือนจะไม่ได้รวบรวมในคอมไพเลอร์ jsxแต่การใช้แผนที่ในคำตอบของ FakeRainBrigand ด้านล่างดูเหมือนจะรวบรวมได้อย่างถูกต้อง
rav

9
ฉันสัญญาได้ว่าตัวอย่างสุดท้ายยังคงรวบรวมอย่างถูกต้องในคอมไพเลอร์ JSX ล่าสุด
Sophie Alpert

3
มันใช้งานได้ดี คำตอบของ FakeRainBrigand ใช้ได้กับการทำซ้ำอาร์เรย์อย่างง่าย แต่คำตอบนี้เป็นสิ่งจำเป็นสำหรับสถานการณ์ที่คุณไม่สามารถใช้งานได้map(เช่นคุณไม่มีคอลเลกชันที่เก็บไว้ในตัวแปร)
เคลวิน

52
ตอบสนองความต้องการที่จะปรับปรุง Dom อย่างมีประสิทธิภาพในกรณีนี้ผู้ปกครองควรกำหนดให้keyกับแต่ละ childern REF: facebook.github.io/react/docs/…
qsun

7
ตัวอย่างนี้จะใช้งานได้ แต่พลาดบิตสำคัญบางอย่างเช่นkeyคุณสมบัติและยังมีรูปแบบโค้ดที่ไม่ได้ใช้จริงใน React code-base โปรดพิจารณาคำตอบนี้stackoverflow.com/questions/22876978/loop-inside-react-jsx/ ......เป็นคำตอบที่ถูกต้อง
okonetchnikov

866

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

หากนี่เป็นรหัสของคุณด้วย for for loop:

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

43
แผนที่เหมาะสมกว่าหาก iteratee เป็นอาร์เรย์ ห่วงสำหรับมีความเหมาะสมถ้ามันเป็นจำนวน
รหัส Whisperer

26
<tbody>{objects.map((o, i) => <ObjectRow obj={o} key={i}/>}</tbody>ใช้การสนับสนุน ES6 หรือ Babel ของ Reactify
Distortum

3
+1 ฉันยังใช้สิ่งนี้กับ ul (รายการที่ไม่ได้เรียงลำดับ) <ul> {objects.map((object:string,i:number)=>{ return <li>{object}</li> })} </ul>ใช้ TypeScript
Roberto C Navarro

5
นี่เป็นสิ่งที่ดี แต่คุณไม่สามารถแมปบนวัตถุ .. สำหรับสิ่งที่ฉันจะใช้for..in
Damon

4
โปรดจำไว้ว่าลำดับของคีย์นั้นไม่ได้ผลเมื่อใช้ Object.keys ฉันพบว่าการเรียงลำดับของคีย์นั้นทำได้ดีและเรียงลำดับตามตัวอักษรของวัตถุหากจำเป็น ที่ช่วยให้ฉันเขียนรหัสเช่นthis.props.order.map((k)=><ObjectRow key={k} {...this.props.items[k]} />)
tgrrr

443

หากคุณยังไม่มีอาร์เรย์ที่map()ชอบคำตอบของ @ FakeRainBrigand และต้องการอินไลน์เพื่อให้เค้าโครงแหล่งที่มาสอดคล้องกับเอาต์พุตใกล้กว่าคำตอบของ @ SophieAlpert:

ด้วย ES2015 (ES6) ไวยากรณ์ (ฟังก์ชั่นการแพร่กระจายและลูกศร)

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

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

Re: transpiling กับบาเบลของหน้าคำเตือนบอกว่าArray.fromเป็นสิ่งจำเป็นสำหรับการแพร่กระจาย แต่ในปัจจุบัน ( v5.8.23) Arrayที่ดูเหมือนจะไม่เป็นกรณีที่เมื่อการแพร่กระจายที่เกิดขึ้นจริง ฉันมีปัญหาเอกสารเปิดให้ชี้แจงว่า แต่ใช้ความเสี่ยงของคุณเองหรือ polyfill

วานิลลา 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>
  );
}

ด้วยไวยากรณ์และArrayวิธีการES2015

ด้วยArray.prototype.fillคุณสามารถทำสิ่งนี้แทนการใช้สเปรดดังที่แสดงด้านบน:

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

(ฉันคิดว่าคุณสามารถละเว้นการโต้แย้งได้fill()แต่ฉันไม่ได้ 100% เลย) ขอบคุณ @FakeRainBrigand สำหรับการแก้ไขข้อผิดพลาดของฉันในfill()โซลูชันรุ่นก่อนหน้า(ดูการแก้ไข)

key

ในทุกกรณีkeyattr จะลดการเตือนด้วยการสร้างการพัฒนา แต่ไม่สามารถเข้าถึงได้ในเด็ก คุณสามารถผ่าน attr พิเศษถ้าคุณต้องการให้ดัชนีมีอยู่ในเด็ก ดูรายการและกุญแจสำหรับการสนทนา


2
เกี่ยวกับyieldอะไร การผลักองค์ประกอบเข้าไปในอาร์เรย์กลางนั้นน่าเกลียดเมื่อเรามีเครื่องกำเนิดไฟฟ้า พวกเขาทำงานหรือไม่
mpen

2
@ มาร์คฉันไม่รู้ว่าเครื่องกำเนิดไฟฟ้าใช้งานได้จริงที่นี่ สิ่งสำคัญสำหรับสิ่งนี้ในบริบทของ JSX คือนิพจน์ที่ส่งกลับอาร์เรย์ ดังนั้นถ้าคุณจะใช้เครื่องกำเนิดไฟฟ้าอย่างใดคุณก็อาจจะแพร่กระจายมันและมันอาจจะเป็น verbose มากกว่าโซลูชั่นที่ใช้ ES2015 ที่นี่
JMM

2
verbose นี้เป็นอย่างไรมากขึ้น? และทำไม JSX ถึงไม่ยอมรับการทำซ้ำ ๆ ไม่ใช่แค่อาร์เรย์?
mpen

2
@ Mark นั่นเป็นจริงverbose น้อยกว่า (ES5) ตัวอย่าง IIFE ที่ฉันใช้ แต่มัน verbose มากขึ้นกว่า[...Array(x)].map(() => <El />))รุ่นซึ่งฉันคิดว่าเป็นสง่าที่สุดและทำไมฉันจึงให้มัน Re: คำถามที่สองนั่นเป็นจุดที่ดี ดูเหมือนจะไม่มีอะไรเกี่ยวกับ JSX ที่ห้ามมันดังนั้นมันขึ้นอยู่กับสิ่งที่ React หรือผู้บริโภคอื่นของการแปลง JSX ทำกับข้อโต้แย้งเด็ก ๆ ซึ่งฉันไม่สามารถพูดได้โดยไม่ได้ดูแหล่งที่มา คุณรู้หรือไม่ มันเป็นคำถามที่น่าสนใจ
JMM

3
@corysimmons ป, fill()ขอบคุณสำหรับข้อมูลเกี่ยวกับ ตอนนี้ฉันจำได้แล้วว่าเหตุผลที่ฉันลังเลอยู่นั่นคือคำถามเกี่ยวกับการระบุตัวเลือกของพารามิเตอร์ในข้อมูลจำเพาะ ES (ต้องดูในบางครั้ง) เครื่องหมายจุลภาคเป็นเพียงวิธีในการกำจัดองค์ประกอบอาร์เรย์ - ในกรณีนี้คือองค์ประกอบแรก คุณสามารถทำเช่นนั้นได้ถ้าคุณต้องการให้ดัชนีนั้นมาจาก 1..length ของอาเรย์ที่คุณกำลังแพร่กระจายมากกว่า 0..length-1 ของสเปรดอาเรย์ (เพราะองค์ประกอบที่มีส่วนร่วมนั้นมีส่วนทำให้ความยาวของอาเรย์และดอน ' ไม่มีคุณสมบัติที่สอดคล้องกัน)
JMM

85

เพียงใช้วิธีmap Arrayด้วยไวยากรณ์ ES6:

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

อย่าลืมkeyทรัพย์สิน


ฉันเพิ่มปุ่ม 'Math.random ()' แบบสุ่มแทนรหัสมันไม่ทำงานเมื่อ setState ในเด็กมีความคิดว่าทำไม
Oliver D

82

ใช้แผนที่อาร์เรย์ฟังก์ชั่นเป็นวิธีที่ใช้กันมากที่จะห่วงผ่านอาร์เรย์ขององค์ประกอบและสร้างส่วนประกอบตามพวกเขาในการตอบสนองนี้เป็นวิธีที่ดีในการทำวงซึ่งเป็นรักที่มีประสิทธิภาพและวิธีที่เป็นระเบียบเรียบร้อยในการทำลูปของคุณในJSXมันไม่ได้เท่านั้น วิธีที่จะทำ แต่วิธีที่ต้องการ

นอกจากนี้อย่าลืมว่ามีคีย์เฉพาะสำหรับแต่ละการวนซ้ำตามที่ต้องการ ฟังก์ชั่นแผนที่สร้างดัชนีที่ไม่ซ้ำกันจาก 0 แต่ไม่แนะนำให้ใช้กับดัชนีที่ผลิต แต่ถ้าค่าของคุณไม่ซ้ำกันหรือมีคีย์ที่ไม่ซ้ำกันคุณสามารถใช้พวกเขา:

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

นอกจากนี้ไม่กี่บรรทัดจากMDNถ้าคุณไม่คุ้นเคยกับฟังก์ชั่นแผนที่บน Array:

แผนที่เรียกฟังก์ชั่นการโทรกลับที่จัดไว้ให้หนึ่งครั้งสำหรับแต่ละองค์ประกอบในอาร์เรย์ตามลำดับและสร้างอาร์เรย์ใหม่จากผลลัพธ์ การเรียกกลับถูกเรียกใช้เฉพาะสำหรับดัชนีของอาร์เรย์ที่มีค่าที่กำหนดรวมถึงไม่ได้กำหนด มันไม่ได้ถูกเรียกสำหรับอิลิเมนต์ที่หายไปของอาเรย์ (นั่นคือดัชนีที่ไม่เคยถูกตั้งค่าซึ่งถูกลบไปแล้วหรือที่ไม่เคยได้รับการกำหนดค่า)

การเรียกกลับถูกเรียกด้วยสามอาร์กิวเมนต์: ค่าขององค์ประกอบ, ดัชนีขององค์ประกอบและวัตถุ Array ที่ถูกสำรวจ

หากพารามิเตอร์ thisArg มีการจัดทำแผนที่จะใช้เป็นค่าโทรกลับของค่านี้ มิฉะนั้นค่าที่ไม่ได้กำหนดจะถูกใช้เป็นค่านี้ ค่านี้ในท้ายที่สุดสามารถสังเกตได้โดยการโทรกลับจะถูกกำหนดตามกฎปกติสำหรับการพิจารณาสิ่งนี้เห็นโดยฟังก์ชั่น

แผนที่ไม่ได้กลายพันธุ์อาเรย์ที่มันถูกเรียก (แม้ว่าการโทรกลับถ้าถูกเรียกอาจทำเช่นนั้น)


Array#mapไม่ใช่ async!
philraj

52

หากคุณใช้ 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>
        );
    }
}

1
Array.prototype.map อาจเป็นตัวเลือกที่ดีถ้าคุณไม่รวมไลบรารี่เช่น lodash developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
Isaiah Gray

1
@IsaiahGrey เฉพาะเมื่อคุณมีอาร์เรย์แล้ว บางครั้งคุณต้องการทำซ้ำสิ่งสองสามครั้ง
mpen

1
แน่นอน! ล็อตของวิธีการที่แตกต่างกันอย่างแน่นอนขึ้นอยู่กับข้อมูลจริง ฉันพบว่าบ่อยครั้งกว่าที่ไม่ได้อยู่ในกระบวนการพัฒนาของเราเราสามารถใส่แผนที่ได้อย่างเหมาะสมเพราะรูปแบบข้อมูลเป็นอย่างไร ตัวอย่างที่ดีในการใช้ lodash! Btw คุณใช้ไวยากรณ์ initializer คุณสมบัติเพื่อผูกเมธอดของคุณกับคอมโพเนนต์ของคุณหรือไม่?
Isaiah Gray

4
@IsaiahGrey ผมคิดว่าพวกเขากำลังเรียกว่าเพียงแค่ ES6 คำจำกัดความของวิธีการ
mpen


34

ฉันรู้ว่านี่เป็นเธรดเก่า แต่คุณอาจต้องการเช็คเอาต์เทมเพลต Reactซึ่งจะช่วยให้คุณใช้เทมเพลตสไตล์ jsx ในการตอบสนองพร้อมกับคำสั่งบางอย่าง (เช่น rt-repeat)

ตัวอย่างของคุณถ้าคุณใช้ react-templates จะเป็น:

<tbody>
     <ObjectRow rt-repeat="obj in objects"/>
</tbody>

เหตุใดจึงต้องใช้ไลบรารีเพิ่มเติมในขณะที่จาวาสคริปต์ธรรมดาได้ให้วิธีแก้ไขปัญหากับลูปหรือ Array.prototype.map หลายชนิดเพื่อแก้ปัญหาแล้ว ฉันเองได้ใช้จาวาสคริปต์ธรรมดาทั้งสองในโครงการปัจจุบันซึ่งทำงานได้ดี การมีนิสัยการใช้จาวาสคริปต์ธรรมดาทุกครั้งที่เป็นไปได้ช่วยให้ฉันพัฒนาทักษะของฉันในจาวาสคริปต์ ฉันใช้ไลบรารีเพิ่มเติมเฉพาะเมื่อดูเหมือนว่าจะยากที่จะหาวิธีแก้ปัญหาสำหรับปัญหาบางอย่างเช่นการกำหนดเส้นทางด้วย React-Router
Lex Soft

27

การทำเช่นนี้มีหลายวิธี ในที่สุด 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>
      {(() => {
        const rows = [];
        for (let i = 0; i < objectRows.length; i++) {
          rows.push(<ObjectRow key={i} data={objectRows[i]} />);
        }
        return rows;
      })()}
    </tbody>
  );
}

2
คำตอบที่ยอดเยี่ยม: เทคนิคต่าง ๆ ทั้งหมดใช้เพียงจาวาสคริปต์ธรรมดาที่แสดงพลังของจาวาสคริปต์ขอบคุณวิธีการต่าง ๆ ในการทำงานที่คล้ายกัน
Lex Soft

24

ถ้า numrows เป็นอาร์เรย์และมันง่ายมาก

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

Array data type ใน React นั้นดีกว่าอาเรย์สามารถสำรองอาเรย์ใหม่และตัวกรองการสนับสนุนลด ฯลฯ


นี่ไม่ใช่คำตอบที่ดีเพราะมันไม่ได้ใช้ประโยชน์จากกุญแจ
kojow7

21

มีหลายคำตอบที่ชี้ไปยังการใช้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 คุณสมบัติติดตั้งอยู่ที่นี่


เมื่อจัดการกับข้อมูล JSON เช่นเมื่อดึงข้อมูลจากฐานข้อมูลโดยใช้ fetch API ฉันใช้วิธี Array.prototype.map มันเป็นวิธีที่สะดวกและพิสูจน์แล้วสำหรับวัตถุประสงค์นั้น
Lex Soft

17

ในการวนซ้ำหลายครั้งและกลับมาคุณสามารถทำได้ด้วยความช่วยเหลือfromและmap:

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

ที่ไหน i = number of times


หากคุณต้องการกำหนดรหัสคีย์ที่ไม่ซ้ำให้กับคอมโพเนนต์ที่แสดงผลคุณสามารถใช้React.Children.toArrayตามที่เสนอในเอกสารตอบโต้

React.Children.toArray

ส่งคืนโครงสร้างข้อมูลทึบแสงเด็ก ๆ เป็นอาเรย์แบนพร้อมคีย์ที่กำหนดให้กับเด็กแต่ละคน มีประโยชน์ถ้าคุณต้องการจัดการคอลเลกชันของเด็ก ๆ ในวิธีการเรนเดอร์โดยเฉพาะอย่างยิ่งถ้าคุณต้องการเรียงลำดับใหม่หรือแบ่งส่วนนี้

บันทึก:

React.Children.toArray()เปลี่ยนคีย์เพื่อรักษาซีแมนทิกส์ของอาร์เรย์ที่ซ้อนกันเมื่อรายชื่อแบนของเด็ก ๆ นั่นคือ toArray นำหน้าแต่ละคีย์ในอาร์เรย์ที่ส่งคืนเพื่อให้คีย์ของแต่ละองค์ประกอบถูกกำหนดขอบเขตไปยังอาร์เรย์อินพุตที่มีอยู่

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

17

หากคุณเลือกที่จะแปลงภายในนี้ผลตอบแทน ()ของการแสดงผลวิธีการเลือกที่ง่ายที่สุดจะใช้แผนที่ ()วิธีการ แม็พอาร์เรย์ของคุณลงในไวยากรณ์ JSX โดยใช้ฟังก์ชั่น map () ดังที่แสดงด้านล่าง ( ใช้ไวยากรณ์ ES6 )


ส่วนประกอบภายในของผู้ปกครอง :

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

โปรดทราบว่าkeyแอตทริบิวต์ที่เพิ่มไปยังองค์ประกอบลูกของคุณ หากคุณไม่ได้ระบุแอตทริบิวต์ที่สำคัญคุณสามารถดูคำเตือนต่อไปนี้บนคอนโซลของคุณ

คำเตือน: เด็กแต่ละคนในอาร์เรย์หรือตัววนซ้ำควรมีเสา "คีย์" ที่ไม่ซ้ำกัน

หมายเหตุ:หนึ่งคนทำผิดพลาดทำคือใช้indexเป็นกุญแจสำคัญเมื่อ iterating ใช้indexขององค์ประกอบเป็นกุญแจสำคัญคือการป้องกันรูปแบบและคุณสามารถอ่านเพิ่มเติมได้ที่นี่ กล่าวโดยย่อถ้าไม่ใช่รายการคงที่ไม่เคยใช้indexเป็นกุญแจ


ตอนนี้ที่องค์ประกอบObjectRowคุณสามารถเข้าถึงวัตถุได้จากคุณสมบัติ

องค์ประกอบ Inside ObjectRow

const { object } = this.props

หรือ

const object = this.props.object

สิ่งนี้ควรดึงข้อมูลวัตถุที่คุณส่งจากคอมโพเนนต์พาเรนต์ไปยังตัวแปรobjectในองค์ประกอบObjectRow ตอนนี้คุณสามารถคายค่าในวัตถุนั้นตามวัตถุประสงค์ของคุณ


การอ้างอิง:

วิธีการ map () ใน Javascript

ECMA Script 6 หรือ ES6


16

ให้เราบอกว่าเรามีรายการอยู่ในสถานะของคุณ:

[{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>

ฉันคิดว่าคุณอาจต้องกำจัด {} หลังแผนที่ (รายการ) ซึ่งดูเหมือนว่าจะใช้งานได้สำหรับฉัน
เอียน

15

ความเป็นไปได้ของ 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>

15

... หรือคุณสามารถเตรียมชุดของวัตถุและแมปไปยังฟังก์ชันเพื่อให้ได้ผลลัพธ์ที่ต้องการ ฉันชอบสิ่งนี้เพราะมันช่วยให้ฉันรักษาแนวปฏิบัติที่ดีในการเขียนโค้ดโดยไม่ต้องใช้ตรรกะในการกลับมาแสดงผล

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

15

เพียงใช้.map()วนรอบคอลเลกชันของคุณและส่งคืน<ObjectRow>สินค้าพร้อมอุปกรณ์ประกอบฉากจากการทำซ้ำแต่ละครั้ง

สมมติว่าobjectsเป็นอาเรย์ที่ไหนสักแห่ง ...

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

15

ES2015 Array.fromพร้อมฟังก์ชันแผนที่ + แป้น

หากคุณไม่มีอะไรที่.map()คุณสามารถใช้Array.from()กับmapฟังก์ชั่นการทำซ้ำองค์ประกอบ:

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

15

ฉันใช้สิ่งนี้:

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

PS: อย่าลืมกุญแจหรือคุณจะได้รับคำเตือนมากมาย!


หรือใช้ดัชนีอาร์เรย์หากรายการของคุณไม่มี.Idคุณสมบัติเช่นitems.map( (item, index) => <Foo key={index}>{item}</Foo>
2017

13

renderฉันมักจะชอบวิธีการที่โปรแกรมตรรกะที่เกิดขึ้นนอกค่าตอบแทนของ สิ่งนี้จะช่วยรักษาสิ่งที่แสดงผลได้ง่าย

ดังนั้นฉันอาจทำสิ่งที่ชอบ:

import _ from 'lodash';

...

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

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

เป็นที่ยอมรับว่าเป็นรหัสจำนวนเล็กน้อยที่ฝังไว้ซึ่งอาจทำงานได้ดี


แฟนตัวยงของแผนที่ Lodash สำหรับวนซ้ำวัตถุ ฉันอยากจะimport { map } from 'lodash'ให้คุณไม่ได้นำเข้าฟังก์ชั่น lodash ทั้งหมดหากคุณไม่ต้องการมัน
ยืด 0

วันนี้เราไม่จำเป็นต้องมีแผนที่ lodash - เพียงแมปไปที่อาร์เรย์โดยตรง
Adam Donahue

ใช่ แต่คุณไม่สามารถวนลูปผ่านวัตถุที่มี es6 map()เพียงอาร์เรย์เท่านั้น นั่นคือสิ่งที่ฉันบอกว่า lodash นั้นดีสำหรับการวนลูปวัตถุ
ยืด 0

ฉันคิดว่าคุณหมายถึงobjectsในรายการสิ่งผิดพลาดของฉัน
Adam Donahue

12

แน่นอนคุณสามารถแก้ปัญหาด้วย. map ตามที่แนะนำโดยคำตอบอื่น ๆ หากคุณใช้ Babel อยู่แล้วคุณสามารถคิดถึงการใช้jsx-control-statements พวกเขาต้องการการตั้งค่าเล็กน้อย แต่ฉันคิดว่ามันมีค่าในแง่ของความสามารถในการอ่าน (โดยเฉพาะสำหรับนักพัฒนาที่ไม่ตอบสนอง) หากคุณใช้ linter ยังมีeslint-plugin-jsx-control-statement


12

รหัส JSX ของคุณจะรวบรวมเป็นรหัส JavaScript บริสุทธิ์แท็กใด ๆ จะถูกแทนที่ด้วยReactElementวัตถุ ใน JavaScript คุณไม่สามารถเรียกใช้ฟังก์ชันได้หลายครั้งเพื่อรวบรวมตัวแปรที่ส่งคืน

เป็นสิ่งผิดกฎหมายวิธีเดียวคือใช้อาร์เรย์เพื่อเก็บฟังก์ชันที่ส่งคืนตัวแปร

หรือคุณสามารถใช้Array.prototype.mapซึ่งมีให้ตั้งแต่ JavaScript ES5เพื่อจัดการสถานการณ์นี้

บางทีเราสามารถเขียนคอมไพเลอร์อื่น ๆ เพื่อสร้างไวยากรณ์ JSX ใหม่ที่จะใช้ฟังก์ชั่นการทำซ้ำเช่นเดียวกับของเชิงมุมng-repeat


12

สามารถทำได้หลายวิธี

  1. ตามที่แนะนำข้างต้นก่อนที่จะreturnเก็บองค์ประกอบทั้งหมดในอาร์เรย์
  2. วนเข้าไปด้านใน 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>
    )

ใช่. ในโครงการปัจจุบันของฉันฉันใช้วิธีที่ 1 เช่นการใช้ Array.prototype, forEach () วิธีการสร้างองค์ประกอบเลือก HTML ซึ่งบรรจุด้วยข้อมูลจากฐานข้อมูล อย่างไรก็ตามฉันน่าจะแทนที่พวกเขาด้วยวิธี Array.prototype.map () เนื่องจากวิธีการแผนที่ดูกะทัดรัดกว่า (รหัสน้อยกว่า)
Lex Soft

10

นี่เป็นวิธีแก้ปัญหาง่ายๆ

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

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


เมื่อสร้างองค์ประกอบเลือก html เทคนิคที่คล้ายกันนี้เป็นสิ่งที่อยู่ในใจของฉันก่อนดังนั้นฉันจึงใช้แม้ว่าฉันจะใช้วิธี forEach () แต่เมื่อฉันอ่านเอกสาร React ในหัวข้อของรายการและคีย์ฉันพบว่าพวกเขาใช้วิธีการ map () ตามที่แสดงโดยคำตอบหลายข้อที่นี่ นี่ทำให้ฉันคิดว่ามันเป็นวิธีที่ต้องการ ฉันเห็นด้วยเนื่องจากมันดูกะทัดรัดกว่า (ใช้รหัสน้อยลง)
Lex Soft

9

เนื่องจากคุณกำลังเขียนไวยากรณ์ Javascript ภายในโค้ด JSX คุณต้องล้อม Javascript ของคุณด้วยเครื่องหมายปีกกา

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

9

นี่คือตัวอย่างจาก React doc: Expressions JavaScript 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>
  );
}

โปรดสังเกตว่าคีย์มีความสำคัญมากเพราะใช้คีย์เพื่อทำซ้ำข้อมูลในอาร์เรย์




8

เป็นคำถามที่ดีมาก

ฉันจะทำอย่างไรเมื่อฉันต้องการเพิ่มจำนวนองค์ประกอบให้ใช้ฟังก์ชั่นตัวช่วย

กำหนดฟังก์ชั่นที่ส่งคืน JSX:

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

//... in JSX

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

8

คุณยังสามารถใช้ฟังก์ชั่นที่เรียกตนเองได้:

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

           })()}
        </tbody>

การใช้ฟังก์ชั่นที่ไม่ระบุชื่อในการสร้างภาพนั้นไม่ถือเป็นแนวปฏิบัติที่ดีในการตอบสนองเนื่องจากฟังก์ชั่นเหล่านี้จำเป็นต้องถูกสร้างขึ้นใหม่หรือทิ้งในการแสดงผลแต่ละครั้ง
Vlatko Vlahek

@VlatkoVlahek คุณเข้าใจผิดว่าอุปกรณ์ประกอบฉากถูกสร้างขึ้นใหม่ในแต่ละรอบการแสดงผลซึ่งอาจนำไปสู่ประสิทธิภาพที่แย่ลงในวงกว้าง การสร้างฟังก์ชั่นที่ไม่ระบุชื่อที่อื่นจะไม่ส่งผลต่อประสิทธิภาพในทางที่สำคัญ
Emile Bergeron

1
@EmileBergeron นี่เป็นเวลาที่ผ่านมาฮ่าฮ่า ฉันเห็นด้วยถ้านี่ไม่ได้ใช้เป็นเสาค้ำก็ไม่มีความแตกต่าง
Vlatko Vlahek
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.