Come eseguire il loop e il rendering di elementi in React.js senza una matrice di oggetti da mappare?


146

Sto provando a convertire un componente jQuery in React.js e una delle cose con cui ho difficoltà è il rendering di n numero di elementi basato su un ciclo for.

Capisco che questo non è possibile o consigliato e che laddove esiste un array nel modello ha perfettamente senso utilizzarlo map. Va bene, ma che dire di quando non si dispone di un array? Invece hai un valore numerico che equivale a un determinato numero di elementi da rendere, quindi cosa dovresti fare?

Ecco il mio esempio, voglio aggiungere un prefisso a un elemento con un numero arbitrario di tag span in base al suo livello gerarchico. Quindi a livello 3, voglio 3 tag span prima dell'elemento di testo.

In javascript:

for (var i = 0; i < level; i++) {
    $el.append('<span class="indent"></span>');
}
$el.append('Some text value');

Non riesco a ottenere questo o qualcosa di simile al lavoro in un componente JSX React.js. Invece ho dovuto fare quanto segue, prima costruendo un array temporaneo della lunghezza corretta e quindi eseguendo il looping dell'array.

React.js

render: function() {
  var tmp = [];
  for (var i = 0; i < this.props.level; i++) {
    tmp.push(i);
  }
  var indents = tmp.map(function (i) {
    return (
      <span className='indent'></span>
    );
  });

  return (
    ...
    {indents}
    "Some text value"
    ...
  );
}

Sicuramente questo non può essere il migliore o l'unico modo per raggiungere questo obiettivo? Cosa mi sto perdendo?



anche tu potresti farlo: jsfiddle.net/crl/69z2wepo/19804
caub

Risposte:


242

Aggiornato: a partire da React> 0,16

Il metodo di rendering non deve necessariamente restituire un singolo elemento. È inoltre possibile restituire un array.

var indents = [];
for (var i = 0; i < this.props.level; i++) {
  indents.push(<span className='indent' key={i}></span>);
}
return indents;

O

return this.props.level.map((item, index) => (
    <span className="indent" key={index}>
        {index}
    </span>
));

Documenti qui che spiegano i bambini JSX


VECCHIO:

Puoi invece usare un loop

var indents = [];
for (var i = 0; i < this.props.level; i++) {
  indents.push(<span className='indent' key={i}></span>);
}
return (
   <div>
    {indents}
    "Some text value"
   </div>
);

Puoi anche usare .map e fantasia es6

return (
   <div>
    {this.props.level.map((item, index) => (
       <span className='indent' key={index} />
    ))}
    "Some text value"
   </div>
);

Inoltre, devi racchiudere il valore restituito in un contenitore. Ho usato div nell'esempio sopra

Come dicono i documenti qui

Attualmente, nel rendering di un componente, è possibile restituire solo un nodo; se hai, diciamo, un elenco di div da restituire, devi avvolgere i tuoi componenti in un div, span o qualsiasi altro componente.


1
Funziona, ed è molto più semplice grazie. Sì, sono consapevole del fatto che devi racchiudere il valore restituito nel contenitore, lo sto già facendo mancando l'esempio.
Jonathan Miles,

2
aggiungi le chiavi all'interno del loop. le chiavi sono importanti per reagire.
Aamir Afridi,

4
ti ho cercato per tutta la vita
Olleh

2
@ElgsQianChen Non è possibile. Deve essere avvolto con un tag. Se {indents} restituisce un singolo elemento dom con contenuto al suo interno, allora va bene
Dhiraj

2
Non capisco perché il metodo della mappa sia menzionato in questa risposta, poiché funziona solo per gli oggetti Array, cosa che la domanda afferma chiaramente non è il caso.
flukyspore,

47

Ecco un esempio più funzionale con alcune funzionalità ES6:

'use strict';

const React = require('react');

function renderArticles(articles) {
    if (articles.length > 0) {      
        return articles.map((article, index) => (
            <Article key={index} article={article} />
        ));
    }
    else return [];
}

const Article = ({article}) => {
    return ( 
        <article key={article.id}>
            <a href={article.link}>{article.title}</a>
            <p>{article.description}</p>
        </article>
    );
};

const Articles = React.createClass({
    render() {
        const articles = renderArticles(this.props.articles);

        return (
            <section>
                { articles }
            </section>
        );
    }
});

module.exports = Articles;

1
Questo sembra il modo più "reattivo" per farlo. Passa i valori come oggetti di scena a un altro sottocomponente. Grazie!
Michael Giovanni Pumo,

Questo è fantastico! Perfetto per quando il tuo render () è pesante HTML.
matthew

Per renderlo più ES6 è possibile utilizzare import React from "react"eexport default Articles
jonlink il

1
Questa risposta non tenta nemmeno di rispondere alla domanda. La domanda era chiara: come convertire un for loopin un array (o oggetto) mappabile per renderizzare n numero di oggetti in un componente React senza avere un array di oggetti. La tua soluzione ignora completamente questo fatto e presume che gli oggetti di scena abbiano passato una serie di articoli.
Jonathan Miles,

17

Sto usando Object.keys(chars).map(...)per eseguire il loop nel rendering

// chars = {a:true, b:false, ..., z:false}

render() {
    return (
       <div>
        {chars && Object.keys(chars).map(function(char, idx) {
            return <span key={idx}>{char}</span>;
        }.bind(this))}
        "Some text value"
       </div>
    );
}

La tua risposta ha funzionato per me, ma solo dopo che ho aggiunto chars && ...e .bind(this)alla fine della mia funzione. Sono curioso di sapere perché semplicemente Object...(così via e così via) non ha funzionato. Continuavo a non essere definito.
m00saca,

2
Questo non risponde alla domanda, dice specificamente senza una matrice di oggetti da analizzare e la spiegazione dice esplicitamente che voglio convertire un ciclo for in mappa per il rendering in un componente React. Hai sostituito l'array con un oggetto che non aiuta a rispondere alla domanda o che non aggiunge alcun valore.
Jonathan Miles,

16

Array.from()accetta un oggetto iterabile per la conversione in un array e una funzione di mappa opzionale. È possibile creare un oggetto con una .lengthproprietà come segue:

return Array.from({length: this.props.level}, (item, index) => 
  <span className="indent" key={index}></span>
);

Mi è capitato di vedere la tua domanda dopo aver ascoltato quest'ultima settimana, quindi è stato il modo più rapido per applicare ciò che avevo imparato! syntax.fm/show/043/…
conradj

1
Proprio quello che mi serviva per il rendering del numero X di elementi, grazie!
Liran H,

0

Penso che questo sia il modo più semplice per eseguire il loop in reagire js

<ul>
    {yourarray.map((item)=><li>{item}</li>)}
</ul>

2
Questo non risponde alla domanda, si prega di leggere la domanda per intero prima di provare a rispondere.
Jonathan Miles,

mi ha aiutato a risparmiare tempo.
Ajay Malhotra,
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.