Loop all'interno di React JSX


1279

Sto provando a fare qualcosa di simile in React JSX(dove ObjectRow è un componente separato):

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

Mi rendo conto e capisco perché questo non è valido JSX, dal momento che le JSXmappe per funzionare chiamate. Tuttavia, venendo dalla terra dei modelli ed essendo nuovo JSX, non sono sicuro di come raggiungerei quanto sopra (aggiungendo un componente più volte).


38
È importante notare che in JSX sono necessari i tag {} attorno alla sintassi JavaScript. Questo può aiutare facebook.github.io/react/docs/… .
Isaiah Gray,

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


@OverCoder perché dovresti mettere l'intero ritorno nel tag {} sarebbe => return <h1> {todo.title} </h1> Non è vero?
pravin poudel,

1
@pravinpoudel in realtà quella risposta è vecchia, più simile a let todos = this.props.todos.map(t => <h1>{t.title}</h1>):)
OverCoder il

Risposte:


1205

Pensa come se stessi semplicemente chiamando le funzioni JavaScript. Non è possibile utilizzare un forciclo in cui andrebbero gli argomenti di una chiamata di funzione:

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

Guarda come tbodyviene passato un forloop alla funzione come argomento e, naturalmente, si tratta di un errore di sintassi.

Ma puoi creare un array e poi passarlo come argomento:

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

Puoi usare sostanzialmente la stessa struttura quando lavori con 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>;

Per inciso, il mio esempio JavaScript è quasi esattamente quello in cui si trasforma quell'esempio di JSX. Gioca con Babel REPL per avere un'idea di come funziona JSX.


3
È possibile che il compilatore sia cambiato, poiché questo esempio non sembra compilarsi nel compilatore jsx , ma l'utilizzo di map come nella risposta di FakeRainBrigand di seguito sembra compilarsi correttamente.
rav

9
Posso promettere che l'ultimo esempio si compila ancora correttamente sull'ultimo compilatore JSX.
Sophie Alpert,

3
Funziona bene La risposta di FakeRainBrigand funziona per una semplice iterazione di array, ma questa risposta è indispensabile per gli scenari in cui non è possibile utilizzare map(ad es. Non si dispone di una raccolta memorizzata in una variabile).
Kelvin,

52
React deve aggiornare dom in modo efficiente, in questo caso il genitore dovrebbe assegnare keya ciascun figlio. RIF: facebook.github.io/react/docs/…
qsun

7
Questo esempio funzionerà, ma manca alcuni bit importanti come la keyproprietà e anche uno stile di codice che non è realmente utilizzato nelle basi di codice di React. Si prega di considerare questa risposta stackoverflow.com/questions/22876978/loop-inside-react-jsx/… come corretta.
okonetchnikov,

867

Non sono sicuro se questo funzionerà per la tua situazione, ma spesso la mappa è una buona risposta.

Se questo era il tuo codice con il ciclo for:

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

Puoi scriverlo così con la mappa :

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

Sintassi ES6:

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

43
La mappa ha più senso se l'iterata è una matrice; Un ciclo for è appropriato se è un numero.
Codice Whisperer,

26
<tbody>{objects.map((o, i) => <ObjectRow obj={o} key={i}/>}</tbody>usando il supporto ES6 di Reactify o Babel.
Distortum,

3
+1. Sto anche usando questo con un ul (elenco non ordinato). <ul> {objects.map((object:string,i:number)=>{ return <li>{object}</li> })} </ul>usando TypeScript
Roberto C Navarro il

5
questo è fantastico, ma non è possibile mappare un oggetto .. per quello che usereifor..in
Damon il

4
Tenere presente che l'ordine delle chiavi è arbitrario quando si utilizza Object.keys. Trovo che memorizzare l'ordine delle chiavi separatamente funzioni bene, e anche l'ordine sull'oggetto letterale se necessario. Questo mi permette di scrivere codice comethis.props.order.map((k)=><ObjectRow key={k} {...this.props.items[k]} />)
tgrrr

443

Se non si dispone già di un array per map()apprezzare la risposta di @ FakeRainBrigand e si desidera incorporarlo in modo che il layout di origine corrisponda all'output più vicino della risposta di @ SophieAlpert:

Con sintassi ES2015 (ES6) (funzioni di diffusione e freccia)

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

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

Ri: traspagando con Babele, la sua pagina di avvertenze dice che Array.fromè necessario per la diffusione, ma al momento ( v5.8.23) che non sembra essere il caso quando si diffonde un effettivo Array. Ho un problema di documentazione aperto per chiarirlo. Ma utilizzare a proprio rischio o polifill.

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

Combinazione di tecniche da altre risposte

Mantenere il layout di origine corrispondente all'output, ma rendere più compatta la parte incorporata:

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

Con sintassi e Arraymetodi ES2015

Con Array.prototype.fillte potresti farlo in alternativa all'utilizzo di spread come illustrato sopra:

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

(Penso che potresti davvero omettere qualsiasi argomento fill(), ma non ci sono al 100% su questo.) Grazie a @FakeRainBrigand per aver corretto il mio errore in una versione precedente della fill()soluzione (vedi revisioni).

key

In tutti i casi l' keyattr allevia un avvertimento con la build di sviluppo, ma non è accessibile nel bambino. Puoi passare un attr extra se desideri che l'indice sia disponibile nel bambino. Vedi Liste e chiavi per la discussione.


2
Che dire yield? Inserire elementi in un array intermedio è piuttosto brutto quando abbiamo generatori. Lavorano?
mpen

2
@Mark Non so che i generatori siano davvero applicabili qui. La cosa fondamentale per questo nel contesto di JSX è un'espressione che restituisce un array. Quindi, se avessi usato un generatore in qualche modo, probabilmente lo avresti diffuso comunque, e probabilmente sarebbe più dettagliato delle soluzioni basate su ES2015 qui.
JMM,

2
Come è questo più dettagliato? E perché JSX non dovrebbe accettare alcuna matrice iterabile, non solo?
mpen

2
@Mark Questo è davvero meno dettagliato dell'esempio IIFE (ES5) che ho usato, ma è considerevolmente più dettagliato della [...Array(x)].map(() => <El />))versione, che ritengo sia la più elegante, e perché l'ho descritta. Ri: la seconda domanda, è un ottimo punto. Non sembra esserci nulla su JSX che lo precluda, quindi dipende da ciò che React o un altro consumatore di JSX trasformato fa con gli argomenti dei bambini, cosa che non potrei dire senza guardare alla fonte. Lo sai? È una domanda intrigante.
JMM,

3
@corysimmons Cool, grazie per le informazioni su fill(). Ricordo ora che la ragione per cui ho esitato è una domanda sul modo in cui l'opzione dei parametri è indicata nelle specifiche ES (è necessario esaminarla prima o poi). La virgola è solo un modo per eludere un elemento array - in questo caso il primo. Puoi farlo se vuoi che gli indici siano da 1..lunghezza dell'array che stai diffondendo piuttosto che 0..length-1 dell'array spread (perché gli elementi elisi contribuiscono solo alla lunghezza dell'array e don ' hanno una proprietà corrispondente).
JMM,

85

Semplicemente usando il metodo map Array con sintassi ES6:

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

Non dimenticare la keyproprietà.


Aggiungo una chiave casuale "Math.random ()" invece di id che non funziona bene quando setState all'interno dei bambini, hai idea del perché?
Oliver D,

82

Utilizzando Array mappa funzione è un modo molto comune per collegare attraverso un array di elementi e creare componenti secondo loro in Reagire , questo è un ottimo modo per fare un ciclo che è abbastanza efficiente e modo ordinato di fare i loop in JSX , E ' non è l'unico modo di farlo, ma il modo preferito.

Inoltre, non dimenticare di avere una chiave univoca per ogni iterazione come richiesto. La funzione Mappa crea un indice univoco da 0 ma non è consigliabile utilizzare l'indice prodotto ma se il tuo valore è unico o se esiste una chiave univoca, puoi usarli:

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

Inoltre, poche righe da MDN se non si ha familiarità con la funzione mappa sull'array:

map chiama una funzione di callback fornita una volta per ogni elemento in un array, in ordine, e costruisce un nuovo array dai risultati. il callback viene richiamato solo per gli indici dell'array a cui sono stati assegnati valori, anche non definiti. Non è richiesto per elementi mancanti dell'array (ovvero, indici che non sono mai stati impostati, che sono stati eliminati o ai quali non è mai stato assegnato un valore).

il callback viene invocato con tre argomenti: il valore dell'elemento, l'indice dell'elemento e l'oggetto Array attraversati.

Se un parametro thisArg viene fornito per mappare, verrà utilizzato come callback per questo valore. In caso contrario, verrà utilizzato il valore indefinito come questo valore. Questo valore alla fine osservabile dal callback è determinato secondo le normali regole per determinare ciò visto da una funzione.

map non muta l'array su cui viene chiamato (anche se il callback, se richiamato, può farlo).


Array#mapnon è asincrono!
philraj,

52

Se stai già utilizzando lodash, la _.timesfunzione è utile.

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 potrebbe essere un'ottima opzione qui se non includi una libreria come lodash. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… .
Isaiah Gray,

1
@IsaiahGrey Solo se hai già un array. A volte vuoi solo ripetere alcune volte alcune cose.
Aprire il

1
certo, naturalmente! Ci sono molti approcci diversi a seconda dei dati reali. Ho scoperto che il più delle volte nel nostro processo di sviluppo siamo stati in grado di adattarci alla mappa grazie al modo in cui i dati sono modellati. Ottimo esempio usando lodash! A proposito, stai usando la sintassi dell'inizializzatore di proprietà per associare i tuoi metodi ai componenti?
Isaiah Gray,

4
@IsaiahGrey Penso che siano appena chiamati definizioni del metodo
aprono il

41

Puoi anche estrarre al di fuori del blocco di ritorno:

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

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

34

So che questo è un vecchio thread, ma potresti voler controllare i React Templates , che ti permettono di usare i template in stile jsx in reag, con alcune direttive (come rt-repeat).

Il tuo esempio, se hai utilizzato i modelli di reazione, sarebbe:

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

Perché utilizzare una libreria aggiuntiva mentre javascript semplice ha già fornito una soluzione con vari tipi di for loop o metodo Array.prototype.map per risolvere il problema? Io stesso ho già usato entrambi i semplici modi javascript nel mio progetto attuale che funzionano bene. Avere l'abitudine di usare semplici modi javascript ogni volta che mi aiuta, mi aiuta a migliorare la mia abilità in javascript. Uso librerie aggiuntive solo quando sembra difficile trovare soluzioni a determinati problemi, come l'instradamento con React-Router.
Lex Soft

27

Esistono diversi modi per farlo. JSX alla fine viene compilato in JavaScript, quindi finché scrivi un JavaScript valido, sarai bravo.

La mia risposta mira a consolidare tutti i meravigliosi modi già presentati qui:

Se non si dispone di una matrice di oggetti, semplicemente il numero di righe:

all'interno del returnblocco, creando un Arraye usando Array.prototype.map:

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

all'esterno del returnblocco, utilizzare semplicemente un normale ciclo for JavaScript:

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

espressione di funzione immediatamente invocata:

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

Se hai una matrice di oggetti

all'interno del returnblocco, .map()ogni oggetto a un <ObjectRow>componente:

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

all'esterno del returnblocco, utilizzare semplicemente un normale ciclo for JavaScript:

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

espressione di funzione immediatamente invocata:

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
Grandi risposte: varie tecniche, tutte usano solo javascript semplice che mostra la potenza di javascript, grazie ai suoi vari modi di svolgere compiti simili.
Lex Soft

24

se numrows è un array ed è molto semplice.

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

Il tipo di dati dell'array in React è molto migliore, l'array può supportare il nuovo array e supportare il filtro, ridurre ecc.


Questa non è una risposta decente in quanto non utilizza una chiave.
kojow7,

21

Esistono diverse risposte che indicano l'utilizzo mapdell'istruzione. Ecco un esempio completo utilizzando un iteratore all'interno elenco funzionalità componente alla lista delle funzioni dei componenti sulla base di una struttura dati JSON chiamato caratteristiche .

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

È possibile visualizzare il codice FeatureList completo su GitHub. L' apparecchio di funzionalità è elencato qui .


Quando ho a che fare con i dati JSON, ad esempio durante il recupero dei dati dal database mediante l'API di recupero, mi affido all'utilizzo del metodo Array.prototype.map. È un modo conveniente e provato a tale scopo.
Lex Soft

17

Per eseguire il ciclo più volte e tornare, puoi ottenerlo con l'aiuto di frome map:

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

dove i = number of times


Se si desidera assegnare ID chiave univoci ai componenti renderizzati, è possibile utilizzare React.Children.toArraycome proposto nella documentazione di React

React.Children.toArray

Restituisce la struttura dati opaca figlio come una matrice piatta con le chiavi assegnate a ciascun figlio. Utile se vuoi manipolare raccolte di bambini con i tuoi metodi di rendering, specialmente se vuoi riordinare o suddividere this.props.children prima di trasmetterlo.

Nota:

React.Children.toArray()cambia le chiavi per preservare la semantica delle matrici nidificate quando si appiattiscono gli elenchi di bambini. In altre parole, toArray prefigura ciascuna chiave dell'array restituito in modo che la chiave di ciascun elemento sia associata all'array di input che la contiene.

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

17

Se si sceglie di convertire questo metodo return () del metodo render , l'opzione più semplice sarebbe usare il metodo map () . Mappare l'array nella sintassi JSX utilizzando la funzione map (), come mostrato di seguito ( viene utilizzata la sintassi ES6 ).


Componente genitore interno :

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

Nota l' keyattributo aggiunto al componente figlio. Se non hai fornito un attributo chiave, puoi vedere il seguente avviso sulla tua console.

Avvertenza: ogni figlio di un array o di un iteratore dovrebbe avere un unico "oggetto" di prop.

Nota: un errore comune che le persone fanno è usare indexcome chiave durante l'iterazione, l'uso indexdell'elemento come chiave è un anti-schema e puoi leggere di più qui . In breve, se NON è un elenco statico, non utilizzare mai indexcome chiave.


Ora nel componente ObjectRow , è possibile accedere all'oggetto dalle sue proprietà.

Componente Inside ObjectRow

const { object } = this.props

o

const object = this.props.object

Questo dovrebbe recuperare l'oggetto che hai passato dal componente padre alla variabile objectnel componente ObjectRow . Ora puoi sputare i valori in quell'oggetto in base al tuo scopo.


Riferimenti :

metodo map () in Javascript

ECMA Script 6 o ES6


16

diciamo che abbiamo una serie di articoli nel tuo stato:

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

Penso che potresti aver bisogno di sbarazzarti del {} dopo la mappa (oggetto), che sembrava funzionare per me.
Ian,

15

Una possibilità ES2015 / Babel sta usando una funzione di generatore per creare un array di JSX:

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

...

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

15

... Oppure puoi anche preparare una matrice di oggetti e mapparla su una funzione per ottenere l'output desiderato. Preferisco questo, perché mi aiuta a mantenere la buona pratica della codifica senza logica all'interno del ritorno di 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>
  )
}

15

Basta usare .map()per scorrere la raccolta e restituire gli <ObjectRow>oggetti con oggetti di scena di ogni iterazione.

Supponendo che objectssia un array da qualche parte ...

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

15

ES2015 Array.from con la funzione map + tasto

Se non hai nulla .map()che puoi usare Array.from()con la mapfunzione per ripetere elementi:

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

15

Io lo uso questo:

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

PS: non dimenticare mai la chiave o avrai molti avvisi!


Oppure usa l'indice dell'array se i tuoi articoli non hanno una .Idproprietà, ad esempioitems.map( (item, index) => <Foo key={index}>{item}</Foo>
kontur

13

Tendo a favorire un approccio in cui la logica di programmazione avviene al di fuori del valore di ritorno di render. Questo aiuta a mantenere ciò che in realtà è reso facile da grok.

Quindi probabilmente farei qualcosa del genere:

import _ from 'lodash';

...

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

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

È vero che questa è una quantità così piccola di codice che la sua integrazione potrebbe funzionare bene.


Grande fan della mappa di lodash per scorrere gli oggetti. Sarei propenso a import { map } from 'lodash'non importare tutte le funzioni lodash se non ne hai bisogno.
Stretch0

In questi giorni non abbiamo nemmeno bisogno della mappa lodash: basta mappare direttamente l'array.
Adam Donahue,

Sì, ma non è possibile eseguire il looping di un oggetto con es6 map(), solo array. Questo è quello che stavo dicendo che lodash è buono per avvolgere un oggetto.
Stretch0,

Pensavo intendessi objectscome in un elenco di cose, il mio errore.
Adam Donahue,

12

puoi ovviamente risolvere con una .map come suggerito dall'altra risposta. Se usi già babel, potresti pensare di usare le istruzioni jsx-control. Richiedono un po 'di impostazione, ma penso che valga la pena in termini di leggibilità (specialmente per gli sviluppatori che non reagiscono). Se usi una linter, ci sono anche eslint-plugin-jsx-control-statement


12

Il tuo codice JSX verrà compilato in puro codice JavaScript, eventuali tag verranno sostituiti da ReactElementoggetti. In JavaScript, non è possibile chiamare più volte una funzione per raccogliere le variabili restituite.

È illegale, l'unico modo è utilizzare un array per memorizzare le variabili restituite dalla funzione.

Oppure puoi usare ciò Array.prototype.mapche è disponibile da JavaScript ES5 per gestire questa situazione.

Forse possiamo scrivere un altro compilatore per ricreare una nuova sintassi JSX per implementare una funzione di ripetizione proprio come quella di Angularng-repeat .


12

Questo può essere fatto in molti modi.

  1. Come suggerito sopra, prima di returnmemorizzare tutti gli elementi nell'array
  2. Loop dentro return

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

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

Si. Nel mio progetto attuale, utilizzo il metodo 1, ovvero utilizzando Array.prototype, il metodo forEach () per creare un elemento di selezione HTML popolato dai dati del database. Tuttavia, probabilmente li sostituirò con il metodo Array.prototype.map (), poiché il metodo map sembra più compatto (meno codice).
Lex Soft

10

Ecco una soluzione semplice ad esso.

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

Non è necessario alcun mapping e codice complesso. È sufficiente inviare le righe nell'array e restituire i valori per renderlo.


Durante la creazione dell'elemento html select, questa tecnica simile è stata quella che mi è venuta in mente in primo luogo, quindi l'ho usato, anche se utilizzo il metodo forEach (). Ma quando ho riletto il documento React su argomenti di Elenchi e chiavi, ho scoperto che usano il metodo map () come mostrato anche da diverse risposte qui. Questo mi fa pensare che sia il modo preferito. Sono d'accordo, poiché sembra più compatto (meno codice).
Lex Soft

9

Dato che stai scrivendo la sintassi Javascript all'interno del codice JSX, devi racchiudere il tuo Javascript tra parentesi graffe.

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

9

Ecco un esempio dal documento React: espressioni JavaScript come figli

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

come nel tuo caso, suggerisco di scrivere in questo modo:

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

Nota che la chiave è molto importante, perché React usa la chiave per differenziare i dati nell'array.


9

Lo uso come

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


8

Ottima domanda

Quello che faccio quando voglio aggiungere un certo numero di componenti è usare una funzione di aiuto.

Definire una funzione che restituisce JSX:

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

//... in JSX

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

8

Puoi anche usare una funzione auto-invocante:

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

           })()}
        </tbody>

L'uso di funzioni anonime all'interno di render non è considerato una buona pratica nella reazione, poiché queste funzioni devono essere ricreate o eliminate su ogni nuovo rendering.
Vlatko Vlahek,

@VlatkoVlahek lo stai confondendo con i puntelli di funzione ricreati ad ogni ciclo di rendering, il che potrebbe portare a prestazioni peggiori su larga scala. La creazione di una funzione anonima in qualsiasi altro luogo non influirà in modo significativo sulle prestazioni.
Emile Bergeron,

1
@EmileBergeron Questo è stato un po 'di tempo fa haha. Sono d'accordo se questo non viene utilizzato come prop, non c'è differenza.
Vlatko Vlahek,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.