Vòng lặp bên trong React JSX


1278

Tôi đang cố gắng làm một cái gì đó như sau trong React JSX(trong đó ObjectRow là một thành phần riêng biệt):

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

Tôi nhận ra và hiểu lý do tại sao điều này không hợp lệ JSX, vì JSXbản đồ cho các cuộc gọi chức năng. Tuy nhiên, đến từ đất mẫu và chưa quen JSX, tôi không chắc mình sẽ đạt được những điều trên như thế nào (thêm một thành phần nhiều lần).


38
Điều quan trọng cần lưu ý là trong JSX, bạn cần các thẻ {} xung quanh Cú pháp JavaScript của mình. Điều này có thể giúp facebook.github.io/react/docs/ .
Ê-sai Xám

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


@OverCoder tại sao bạn lại đặt toàn bộ lợi nhuận vào thẻ {}, đó sẽ là => return <h1> {todo.title} </ h1> Phải không?
Pravin poudel

1
@pravinpoudel thực sự câu trả lời đó đã cũ, giống hơn let todos = this.props.todos.map(t => <h1>{t.title}</h1>):)
OverCoder

Câu trả lời:


1205

Hãy nghĩ về nó giống như bạn chỉ đang gọi các hàm JavaScript. Bạn không thể sử dụng một forvòng lặp trong đó các đối số cho một lệnh gọi hàm sẽ đi:

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

Xem cách hàm tbodyđược truyền qua một forvòng lặp dưới dạng đối số và tất nhiên đó là lỗi cú pháp.

Nhưng bạn có thể tạo một mảng và sau đó chuyển nó thành một đối số:

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

Về cơ bản, bạn có thể sử dụng cùng một cấu trúc khi làm việc với 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>;

Ngẫu nhiên, ví dụ JavaScript của tôi gần như chính xác là ví dụ mà JSX chuyển đổi thành. Chơi xung quanh với Babel REPL để cảm nhận về cách hoạt động của JSX.


3
Có thể trình biên dịch đã thay đổi, vì ví dụ này dường như không biên dịch trong trình biên dịch jsx , nhưng sử dụng bản đồ như trong câu trả lời của FakeRainBrigand dưới đây dường như biên dịch chính xác.
rav

9
Tôi có thể hứa rằng ví dụ cuối cùng vẫn biên dịch chính xác trên trình biên dịch JSX mới nhất.
Sophie Alpert

3
Điều này hoạt động tốt. Câu trả lời của FakeRainBrigand hoạt động cho phép lặp mảng đơn giản, nhưng câu trả lời này là bắt buộc đối với các tình huống mà bạn không thể sử dụng map(ví dụ: bạn không có bộ sưu tập được lưu trữ trong một biến).
Kelvin

52
React cần cập nhật dom một cách hiệu quả, trong trường hợp này, cha mẹ nên gán a keycho mỗi childern. REF: facebook.github.io/react/docs/ Từ
qsun

7
Đây là ví dụ sẽ hoạt động, nhưng nó bỏ lỡ một số bit quan trọng như thuộc keytính và cũng là một kiểu mã không thực sự được sử dụng trong các cơ sở mã React. Vui lòng xem câu trả lời này stackoverflow.com/questions/22876978/loop-inside-react-jsx/. Như một câu trả lời đúng.
okonetchnikov

866

Không chắc chắn nếu điều này sẽ làm việc cho tình huống của bạn, nhưng thường bản đồ là một câu trả lời tốt.

Nếu đây là mã của bạn với vòng lặp for:

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

Bạn có thể viết nó như thế này với bản đồ :

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

Cú pháp ES6:

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

43
Bản đồ có ý nghĩa hơn nếu iteratee là một mảng; Một vòng lặp for là thích hợp nếu nó là một số.
Code Whisperer

26
<tbody>{objects.map((o, i) => <ObjectRow obj={o} key={i}/>}</tbody>sử dụng hỗ trợ ES6 của Reactify hoặc Babel.
Distortum

3
+1. Tôi thậm chí đang sử dụng cái này với một ul (danh sách không có thứ tự). <ul> {objects.map((object:string,i:number)=>{ return <li>{object}</li> })} </ul>sử dụng TypeScript
Roberto C Navarro

5
Điều này thật tuyệt, nhưng bạn không thể ánh xạ lên một đối tượng .. vì điều đó tôi sẽ sử dụngfor..in
Damon

4
Hãy nhớ rằng thứ tự của các phím là tùy ý khi sử dụng Object.keys. Tôi thấy rằng việc lưu trữ thứ tự các khóa riêng biệt hoạt động tốt, và cũng là thứ tự trên đối tượng theo nghĩa đen nếu cần thiết. Điều đó cho phép tôi viết mã nhưthis.props.order.map((k)=><ObjectRow key={k} {...this.props.items[k]} />)
tgrrr 15/03/2016

443

Nếu bạn chưa có một mảng để map()thích câu trả lời của @ FakeRainBrigand và muốn nội tuyến này để bố cục nguồn tương ứng với đầu ra gần hơn câu trả lời của @ SophieAlpert:

Với cú pháp ES2015 (ES6) (hàm lây lan và mũi tên)

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

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

Re: dịch mã với Babel, trang thông báo của nó nói rằng điều đó Array.fromlà bắt buộc để lan truyền, nhưng hiện tại ( v5.8.23) dường như không phải là trường hợp khi lan truyền một thực tế Array. Tôi có một vấn đề tài liệu mở để làm rõ điều đó. Nhưng sử dụng có nguy cơ của riêng bạn hoặc polyfill.

Vani ES5

Array.apply

<tbody>
  {Array.apply(0, Array(10)).map(function (x, i) {
    return <ObjectRow key={i} />;
  })}
</tbody>

Nội tuyến 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>

Kết hợp các kỹ thuật từ các câu trả lời khác

Giữ bố cục nguồn tương ứng với đầu ra, nhưng làm cho phần bên trong nhỏ gọn hơn:

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

Với cú pháp & Arrayphương pháp ES2015

Với Array.prototype.fillbạn có thể làm điều này như là một thay thế cho việc sử dụng lây lan như minh họa ở trên:

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

(Tôi nghĩ rằng bạn thực sự có thể bỏ qua bất kỳ đối số cho fill(), nhưng tôi không chắc chắn 100% về điều đó.) Nhờ @FakeRainBrigand cho sửa chữa sai lầm của tôi trong một phiên bản trước đó của fill()giải pháp (xem các phiên bản).

key

Trong mọi trường hợp, keyattr làm giảm bớt một cảnh báo với bản dựng phát triển, nhưng không thể truy cập được ở trẻ. Bạn có thể vượt qua một attr thêm nếu bạn muốn chỉ số có sẵn trong đứa trẻ. Xem Danh sách và Chìa khóa để thảo luận.


2
Thế còn yield? Đẩy các phần tử vào một mảng trung gian là loại xấu xí khi chúng ta có máy phát điện. Họ có làm việc không?
mở

2
@Mark Tôi không biết rằng máy phát điện thực sự có thể áp dụng ở đây. Điều quan trọng cho điều này trong ngữ cảnh của JSX là một biểu thức trả về một mảng. Vì vậy, nếu bạn định sử dụng một trình tạo bằng cách nào đó, có thể bạn sẽ phát tán nó bằng mọi cách và có lẽ nó sẽ dài dòng hơn các giải pháp dựa trên ES2015 ở đây.
JMM

2
Làm thế nào là này tiết hơn? Và tại sao JSX không chấp nhận bất kỳ lần lặp nào, không chỉ các mảng?
mở cửa

2
@Mark Điều đó thực sự ít dài dòng hơn so với ví dụ IIFE (ES5) mà tôi đã sử dụng, nhưng nó dài hơn đáng kể so với [...Array(x)].map(() => <El />))phiên bản, mà tôi nghĩ là thanh lịch nhất, và tại sao tôi lại giới thiệu nó. Re: câu hỏi thứ hai, đó là một điểm tuyệt vời. Dường như không có bất cứ điều gì về JSX loại trừ nó, do đó, nó phụ thuộc vào React hoặc một người tiêu dùng khác của JSX đã làm gì với các đối số trẻ em, mà tôi không thể nói mà không cần nhìn vào nguồn. Bạn có biết? Đó là một câu hỏi hấp dẫn.
JMM

3
@corysimmons Tuyệt, cảm ơn vì thông tin trên fill(). Bây giờ tôi nhớ rằng lý do tôi do dự về điều đó là một câu hỏi về cách tính tùy chọn của các tham số được chỉ định trong thông số ES (đôi khi phải xem xét điều đó). Dấu phẩy chỉ là một cách để tách biệt một phần tử mảng - trong trường hợp này là phần tử đầu tiên. Bạn có thể làm điều đó nếu bạn muốn các chỉ mục có giá trị từ 1. độ dài của mảng bạn đang lan truyền chứ không phải 0..length-1 của mảng trải rộng (vì các phần tử được tách ra chỉ đóng góp vào độ dài của mảng và không ' t có một tài sản tương ứng).
JMM

85

Chỉ cần sử dụng phương thức Map Array với cú pháp ES6:

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

Đừng quên keytài sản.


Tôi thêm một khóa 'Math.random ()' ngẫu nhiên thay vì id nó không hoạt động tốt khi setState bên trong trẻ em, bạn có biết tại sao không?
Oliver D

82

Sử dụng chức năng bản đồ mảng là cách rất phổ biến để lặp qua một mảng các phần tử và tạo các thành phần theo chúng trong React , đây là một cách tuyệt vời để thực hiện một vòng lặp khá hiệu quả và gọn gàng để thực hiện các vòng lặp của bạn trong JSX , Đây không phải là cách duy nhất cách để làm điều đó, nhưng cách ưa thích.

Ngoài ra, đừng quên có một Khóa duy nhất cho mỗi lần lặp theo yêu cầu. Hàm bản đồ tạo một chỉ mục duy nhất từ ​​0 nhưng không nên sử dụng chỉ mục được sản xuất nhưng nếu giá trị của bạn là duy nhất hoặc nếu có một khóa duy nhất, bạn có thể sử dụng chúng:

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

Ngoài ra, một vài dòng từ MDN nếu bạn không quen với chức năng bản đồ trên Mảng:

map gọi hàm gọi lại được cung cấp một lần cho mỗi phần tử trong một mảng, theo thứ tự và xây dựng một mảng mới từ kết quả. gọi lại chỉ được gọi cho các chỉ mục của mảng đã gán các giá trị, bao gồm cả không xác định. Nó không được gọi cho các phần tử bị thiếu của mảng (nghĩa là các chỉ mục chưa bao giờ được đặt, đã bị xóa hoặc chưa bao giờ được gán một giá trị).

gọi lại được gọi với ba đối số: giá trị của phần tử, chỉ mục của phần tử và đối tượng Array được duyệt qua.

Nếu tham số thisArg được cung cấp cho bản đồ, nó sẽ được sử dụng làm giá trị gọi lại này. Mặt khác, giá trị không xác định sẽ được sử dụng làm giá trị này. Giá trị này cuối cùng có thể quan sát được bằng cách gọi lại được xác định theo các quy tắc thông thường để xác định giá trị này được nhìn thấy bởi một hàm.

map không làm biến đổi mảng mà nó được gọi (mặc dù gọi lại, nếu được gọi, có thể làm như vậy).


Array#mapkhông đồng bộ!
philraj

52

Nếu bạn đã sử dụng lodash, _.timeschức năng này rất tiện dụng.

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 có thể là một lựa chọn tuyệt vời ở đây nếu bạn không bao gồm một thư viện như lodash. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ ,.
Ê-sai Xám

1
@IsaiahGrey Chỉ khi bạn đã có một mảng. Đôi khi bạn chỉ muốn lặp lại công cụ một vài lần.
mở

1
tất nhiên rồi Rất nhiều cách tiếp cận khác nhau chắc chắn tùy thuộc vào dữ liệu thực tế. Tôi thấy rằng thường xuyên hơn không phải trong quá trình phát triển của chúng tôi, chúng tôi đã có thể điều chỉnh bản đồ vì dữ liệu được mô hình hóa như thế nào. Ví dụ tuyệt vời bằng cách sử dụng lodash! Btw, bạn đang sử dụng cú pháp khởi tạo thuộc tính để liên kết các phương thức của bạn với các thành phần của bạn?
Ê-sai Xám

4
@IsaiahGrey Tôi nghĩ rằng họ chỉ được gọi là định nghĩa phương thức
ES6

41

Bạn cũng có thể trích xuất bên ngoài khối trả về:

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

    return (<tbody>{rows}</tbody>);
}

34

Tôi biết đây là một chủ đề cũ, nhưng bạn có thể muốn kiểm tra Mẫu React , cho phép bạn sử dụng các mẫu kiểu jsx trong phản ứng, với một vài chỉ thị (như rt-repeat).

Ví dụ của bạn, nếu bạn đã sử dụng các mẫu phản ứng, sẽ là:

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

Tại sao sử dụng thư viện bổ sung trong khi javascript đơn giản đã cung cấp giải pháp với các loại phương thức lặp hoặc Array.prototype.map khác nhau để giải quyết vấn đề? Bản thân tôi đã sử dụng cả hai cách javascript đơn giản trong dự án hiện tại của tôi hoạt động tốt. Có thói quen sử dụng các cách javascript đơn giản bất cứ khi nào có thể giúp tôi cải thiện kỹ năng của mình trong javascript. Tôi chỉ sử dụng các thư viện bổ sung khi có vẻ khó tìm giải pháp cho một số vấn đề nhất định, chẳng hạn như định tuyến bằng React-Router.
Lex Soft

27

Có nhiều cách để làm điều này. Cuối cùng, JSX được biên dịch thành JavaScript, miễn là bạn viết JavaScript hợp lệ, bạn sẽ ổn.

Câu trả lời của tôi nhằm củng cố tất cả những cách tuyệt vời đã được trình bày ở đây:

Nếu bạn không có một mảng đối tượng, chỉ cần số lượng hàng:

trong return khối, tạo Arrayvà sử dụng Array.prototype.map:

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

bên ngoài returnkhối, chỉ cần sử dụng vòng lặp JavaScript bình thường:

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

ngay lập tức gọi biểu thức hàm:

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

Nếu bạn có một mảng các đối tượng

trong returnkhối, .map()mỗi đối tượng<ObjectRow> thành phần:

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

bên ngoài returnkhối, chỉ cần sử dụng vòng lặp JavaScript bình thường:

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

ngay lập tức gọi biểu thức hàm:

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
Câu trả lời tuyệt vời: các kỹ thuật khác nhau, tất cả chỉ sử dụng javascript đơn giản cho thấy sức mạnh của javascript, nhờ vào các cách khác nhau để thực hiện các tác vụ tương tự.
Lex Soft

24

nếu chữ số là một mảng, và nó rất đơn giản.

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

Kiểu dữ liệu mảng trong React rất tốt, mảng có thể sao lưu mảng mới và bộ lọc hỗ trợ, giảm vv.


Đây không phải là một câu trả lời hay vì nó không sử dụng khóa.
kojow7

21

Có một số câu trả lời chỉ ra sử dụng maptuyên bố. Dưới đây là một ví dụ hoàn chỉnh bằng cách sử dụng một trình vòng lặp trong thành phần FeatureList để liệt kê các thành phần Tính năng dựa trên cấu trúc dữ liệu JSON được gọi là các tính năng .

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

Bạn có thể xem mã FeatureList hoàn chỉnh trên GitHub. Các vật cố tính năng được liệt kê ở đây .


Khi xử lý dữ liệu JSON, chẳng hạn như khi truy xuất dữ liệu từ cơ sở dữ liệu bằng cách sử dụng API tìm nạp, tôi dựa vào việc sử dụng phương thức Array.prototype.map. Đó là một cách thuận tiện và đã được chứng minh cho mục đích đó.
Lex Soft

17

Để lặp lại một số lần và trả lại, bạn có thể đạt được điều đó với sự trợ giúp của frommap:

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

Ở đâu i = number of times


Nếu bạn muốn gán ID khóa duy nhất cho các thành phần được kết xuất, bạn có thể sử dụng React.Children.toArraynhư được đề xuất trong tài liệu Phản ứng

Phản ứng.Children.toArray

Trả về cấu trúc dữ liệu mờ của trẻ em dưới dạng một mảng phẳng với các khóa được gán cho mỗi đứa trẻ. Hữu ích nếu bạn muốn thao tác các bộ sưu tập của trẻ em trong các phương thức kết xuất của mình, đặc biệt nếu bạn muốn sắp xếp lại hoặc cắt this.props.children trước khi chuyển nó xuống.

Ghi chú:

React.Children.toArray()thay đổi các khóa để bảo tồn ngữ nghĩa của các mảng lồng nhau khi làm phẳng danh sách của trẻ em. Nghĩa là, toArray tiền tố mỗi khóa trong mảng được trả về sao cho mỗi khóa của phần tử được đặt trong phạm vi mảng đầu vào chứa nó.

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

17

Nếu bạn chọn chuyển đổi phương thức trả lại bên trong này () của phương thức kết xuất , tùy chọn dễ nhất sẽ là sử dụng phương thức map () . Ánh xạ mảng của bạn vào cú pháp JSX bằng hàm map (), như được hiển thị bên dưới ( cú pháp ES6 được sử dụng ).


Thành phần cha mẹ bên trong :

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

Xin lưu ý keythuộc tính được thêm vào thành phần con của bạn. Nếu bạn không cung cấp thuộc tính khóa, bạn có thể thấy cảnh báo sau trên bảng điều khiển của mình.

Cảnh báo: Mỗi đứa trẻ trong một mảng hoặc iterator nên có một "phím" duy nhất.

Lưu ý: Một lỗi phổ biến mà mọi người thường làm là sử dụng indexlàm khóa khi lặp, sử dụng indexphần tử làm khóa là một kiểu chống và bạn có thể đọc thêm về nó ở đây . Nói tóm lại, nếu đó KHÔNG phải là một danh sách tĩnh thì không bao giờ sử dụng indexlàm khóa.


Bây giờ tại thành phần ObjectRow , bạn có thể truy cập đối tượng từ các thuộc tính của nó.

Bên trong thành phần ObjectRow

const { object } = this.props

hoặc là

const object = this.props.object

Điều này sẽ tìm nạp cho bạn đối tượng bạn đã truyền từ thành phần cha mẹ đến biến objecttrong thành phần ObjectRow . Bây giờ bạn có thể phun ra các giá trị trong đối tượng đó theo mục đích của bạn.


Người giới thiệu :

Phương thức map () trong Javascript

Tập lệnh ECMA 6 hoặc ES6


16

hãy để chúng tôi nói rằng chúng tôi có một loạt các mặt hàng trong tiểu bang của bạn:

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

Tôi nghĩ rằng bạn có thể cần phải thoát khỏi {} sau bản đồ (vật phẩm), điều đó dường như có tác dụng với chúng.
Ian

15

Khả năng ES2015 / Babel đang sử dụng hàm tạo để tạo một mảng JSX:

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

...

<tbody>
    {[...jsxLoop(numrows, i =>
        <ObjectRow key={i}/>
    )]}
</tbody>

15

... Hoặc bạn cũng có thể chuẩn bị một mảng các đối tượng và ánh xạ nó tới một hàm để có đầu ra mong muốn. Tôi thích điều này, bởi vì nó giúp tôi duy trì thực hành tốt về mã hóa mà không có logic bên trong sự trở lại của kết xuất.

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

Chỉ cần sử dụng .map()để lặp qua bộ sưu tập của bạn và trả lại <ObjectRow>các mục với đạo cụ từ mỗi lần lặp.

Giả sử objectslà một mảng ở đâu đó ...

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

15

ES2015 Array.from với chức năng bản đồ + phím

Nếu bạn không có gì để .map()bạn có thể sử dụng Array.from()với các mapchức năng để các yếu tố lặp lại:

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

15

Tôi sử dụng cái này:

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

PS: không bao giờ quên chìa khóa hoặc bạn sẽ có rất nhiều cảnh báo!


Hoặc sử dụng chỉ mục mảng nếu các mục của bạn không có thuộc .Idtính, nhưitems.map( (item, index) => <Foo key={index}>{item}</Foo>
kontur 30/03/2017

13

Tôi có xu hướng ủng hộ một cách tiếp cận trong đó logic lập trình xảy ra bên ngoài giá trị trả về của render. Điều này giúp giữ những gì thực sự được hiển thị dễ dàng để mò mẫm.

Vì vậy, tôi có thể làm một cái gì đó như:

import _ from 'lodash';

...

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

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

Phải thừa nhận rằng đây là một lượng nhỏ mã mà nội tuyến có thể hoạt động tốt.


Fan hâm mộ lớn của bản đồ lodash để lặp qua các đối tượng. Tôi sẽ có khuynh hướng để import { map } from 'lodash'bạn không nhập tất cả các hàm lodash nếu bạn không cần chúng.
Kéo dài

Ngày nay, chúng ta thậm chí không cần bản đồ lodash - chỉ cần bản đồ trực tiếp trên mảng.
Adam Donahue

Vâng, nhưng bạn không thể lặp qua một đối tượng với es6 map(), chỉ các mảng. Đó là những gì tôi đã nói lodash là tốt để lặp qua một đối tượng.
Kéo dài

Tôi nghĩ bạn có nghĩa objectslà trong một danh sách các điều, sai lầm của tôi.
Adam Donahue

12

tất nhiên bạn có thể giải quyết bằng một .map theo đề xuất của câu trả lời khác. Nếu bạn đã sử dụng babel, bạn có thể nghĩ về việc sử dụng các câu lệnh kiểm soát jsx Họ yêu cầu một chút cài đặt, nhưng tôi nghĩ rằng nó đáng giá về khả năng đọc (đặc biệt đối với nhà phát triển không phản ứng). Nếu bạn sử dụng một kẻ nói dối, cũng có eslint-plugin-jsx-control-statement


12

Mã JSX của bạn sẽ biên dịch thành mã JavaScript thuần túy, mọi thẻ sẽ được thay thế bởi ReactElementcác đối tượng. Trong JavaScript, bạn không thể gọi một hàm nhiều lần để thu thập các biến được trả về của chúng.

Nó là bất hợp pháp, cách duy nhất là sử dụng một mảng để lưu trữ các biến trả về hàm.

Hoặc bạn có thể sử dụng Array.prototype.mapcó sẵn từ JavaScript ES5 để xử lý tình huống này.

Có lẽ chúng ta có thể viết trình biên dịch khác để tạo lại cú pháp JSX mới để thực hiện chức năng lặp lại giống như của Angularng-repeat .


12

Điều này có thể được thực hiện theo nhiều cách.

  1. Như đã đề xuất ở trên, trước khi returnlưu trữ tất cả các phần tử trong mảng
  2. Vòng lặp bên trong return

    Phương pháp 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>
        )

    Cách 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>
    )

Vâng. Trong dự án hiện tại của tôi, tôi sử dụng phương thức 1, tức là sử dụng phương thức Array.prototype, forEach () để tạo phần tử chọn HTML được điền bởi dữ liệu từ cơ sở dữ liệu. Tuy nhiên, nhiều khả năng tôi sẽ thay thế chúng bằng phương thức Array.prototype.map (), vì phương thức bản đồ trông gọn hơn (ít mã hơn).
Lex Soft

10

Đây là một giải pháp đơn giản cho nó.

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

Không cần ánh xạ và mã phức tạp. Bạn chỉ cần đẩy các hàng thành mảng và trả về các giá trị để hiển thị nó.


Khi tạo phần tử chọn html, kỹ thuật tương tự này là thứ xuất hiện trong đầu tôi, vì vậy tôi đã sử dụng nó, mặc dù tôi sử dụng phương thức forEach (). Nhưng khi tôi đọc lại tài liệu React về các chủ đề của Danh sách và Khóa, tôi thấy rằng họ sử dụng phương thức map () như được hiển thị bởi một số câu trả lời ở đây. Điều này khiến tôi nghĩ rằng đó là cách ưa thích. Tôi đồng ý, vì nó trông gọn hơn (ít mã hơn).
Lex Soft

9

Vì bạn đang viết cú pháp Javascript bên trong mã JSX, bạn cần bọc Javascript của mình trong các dấu ngoặc nhọn.

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

9

Đây là một mẫu từ 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>
  );
}

như trường hợp của bạn, tôi đề nghị viết như thế này:

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

Xin lưu ý Khóa rất quan trọng, vì React sử dụng Khóa để phân biệt dữ liệu trong mảng.


9

Tôi sử dụng nó như

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


8

Câu hỏi tuyệt vời.

Những gì tôi làm khi tôi muốn thêm một số thành phần nhất định là sử dụng chức năng trợ giúp.

Xác định hàm trả về JSX:

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

//... in JSX

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

8

Bạn cũng có thể sử dụng chức năng tự gọi:

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

           })()}
        </tbody>

Sử dụng các hàm ẩn danh trong kết xuất không được coi là một cách thực hành tốt trong phản ứng, vì các hàm này cần được tạo lại hoặc loại bỏ trên mỗi kết xuất lại.
Vlatko Vlahek

@VlatkoVlahek bạn đang nhầm lẫn nó với các đạo cụ chức năng được tạo lại mỗi chu kỳ kết xuất, điều này có thể dẫn đến hiệu suất kém hơn trên quy mô lớn. Tạo chức năng ẩn danh ở bất kỳ nơi nào khác sẽ không ảnh hưởng đến hiệu suất theo bất kỳ cách quan trọng nào.
Emile Bergeron

1
@EmileBergeron Cách đây đã lâu haha. Tôi đồng ý nếu điều này không được sử dụng như một chỗ dựa, không có sự khác biệt.
Vlatko Vlahek
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.