Wie kann man Elemente in React.js schleifen und rendern, ohne dass ein Array von Objekten zugeordnet werden muss?

145

Ich versuche, eine jQuery-Komponente in React.js zu konvertieren, und eines der Dinge, mit denen ich Schwierigkeiten habe, ist das Rendern von n Elementen basierend auf einer for-Schleife.

Ich verstehe, dass dies nicht möglich oder empfohlen ist und dass die Verwendung eines Arrays im Modell durchaus sinnvoll ist map. Das ist in Ordnung, aber was ist, wenn Sie kein Array haben? Stattdessen haben Sie einen numerischen Wert, der einer bestimmten Anzahl von zu rendernden Elementen entspricht. Was sollten Sie dann tun?

Hier ist mein Beispiel: Ich möchte einem Element eine beliebige Anzahl von Span-Tags voranstellen, basierend auf seiner Hierarchieebene. Auf Ebene 3 möchte ich also 3 Span-Tags vor dem Textelement.

In Javascript:

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

Ich kann das oder etwas Ähnliches nicht verstehen, um in einer JSX React.js-Komponente zu arbeiten. Stattdessen musste ich Folgendes tun, zuerst ein temporäres Array mit der richtigen Länge erstellen und dann das Array in einer Schleife durchlaufen.

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

Sicherlich kann dies nicht der beste oder einzige Weg sein, dies zu erreichen? Was vermisse ich?

Jonathan Miles
quelle
Sie können das auch einfach tun: jsfiddle.net/crl/69z2wepo/19804
caub

Antworten:

241

Aktualisiert: Ab React> 0.16

Die Rendermethode muss nicht unbedingt ein einzelnes Element zurückgeben. Ein Array kann auch zurückgegeben werden.

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

ODER

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

Hier finden Sie Informationen zu JSX-Kindern


ALT:

Sie können stattdessen eine Schleife verwenden

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

Sie können auch .map und ausgefallene es6 verwenden

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

Außerdem müssen Sie den Rückgabewert in einen Container einschließen. Ich habe im obigen Beispiel div verwendet

Wie die Dokumente hier sagen

Derzeit können Sie beim Rendern einer Komponente nur einen Knoten zurückgeben. Wenn Sie beispielsweise eine Liste von Divs haben, die zurückgegeben werden sollen, müssen Sie Ihre Komponenten in Div, Span oder eine andere Komponente einschließen.

Dhiraj
quelle
1
Das funktioniert und es ist viel einfacher, danke. Ja, ich bin mir bewusst, dass Sie den Rückgabewert in einen Container einschließen müssen. Ich mache das bereits, es fehlt nur im Beispiel.
Jonathan Miles
2
Fügen Sie Schlüssel innerhalb der Schleife hinzu. Schlüssel sind wichtig für die Reaktion.
Aamir Afridi
4
Ich habe dich mein ganzes Leben lang
gesucht
2
@ElgsQianChen Es ist nicht möglich. Es muss mit einem Etikett umwickelt werden. Wenn {indents} ein einzelnes dom-Element mit darin enthaltenem Inhalt zurückgibt, ist es in
Ordnung
2
Ich verstehe nicht, warum die Kartenmethode in dieser Antwort erwähnt wird, da sie nur für Array-Objekte funktioniert, was in der Frage eindeutig nicht der Fall ist.
Flukyspore
47

Hier ist ein funktionaleres Beispiel mit einigen ES6-Funktionen:

'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;
Dmytro Medvid
quelle
1
Dies scheint der "reaktivste" Weg zu sein, dies zu tun. Übergeben Sie Werte als Requisiten an eine andere Unterkomponente. Vielen Dank!
Michael Giovanni Pumo
Das ist großartig! Perfekt, wenn Ihr render () HTML-schwer ist.
Matthew
Um es mehr ES6 zu machen, könnten Sie import React from "react"undexport default Articles
jonlink
1
Diese Antwort versucht nicht einmal, die Frage zu beantworten. Die Frage war klar, wie man ein for loopArray (oder Objekt) in ein Map-fähiges Array (oder Objekt) konvertiert , um n Elemente in einer React-Komponente zu rendern, ohne ein Array von Elementen zu haben. Ihre Lösung ignoriert diese Tatsache vollständig und geht davon aus, dass eine Reihe von Artikeln von Requisiten übergeben werden.
Jonathan Miles
17

Ich benutze, Object.keys(chars).map(...)um in Render zu schleifen

// 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>
    );
}
Mathdoy
quelle
Ihre Antwort hat bei mir funktioniert, aber erst nachdem ich sie hinzugefügt habe chars && ...und .bind(this)am Ende meiner Funktion. Ich bin gespannt, warum nur Object...(so weiter und so fort) nicht funktioniert hat. Ich wurde immer undefinierter.
m00saca
2
Dies beantwortet die Frage nicht, sondern besagt ausdrücklich, dass ohne ein Array von zu analysierenden Objekten eine for-Schleife zum Rendern in einer React-Komponente in eine Map konvertiert werden soll. Sie haben ein Objekt durch ein Array ersetzt, das die Frage nicht beantwortet, oder einen weiteren Wert hinzugefügt.
Jonathan Miles
16

Array.from()Nimmt ein iterierbares Objekt zum Konvertieren in ein Array und eine optionale Zuordnungsfunktion. Sie können ein Objekt mit einer .lengthEigenschaft wie folgt erstellen :

return Array.from({length: this.props.level}, (item, index) => 
  <span className="indent" key={index}></span>
);
conradj
quelle
Ich habe Ihre Frage zufällig gesehen, nachdem ich sie mir letzte Woche angehört habe. Es war also der schnellste Weg, das Gelernte anzuwenden! syntax.fm/show/043/…
conradj
1
Genau das, was ich zum Rendern von X Elementen brauchte, danke!
Liran H
0

Ich denke, dies ist der einfachste Weg, um js zu reagieren

<ul>
    {yourarray.map((item)=><li>{item}</li>)}
</ul>
Nasar uddin
quelle
2
Dies beantwortet die Frage nicht. Bitte lesen Sie die Frage vollständig durch, bevor Sie versuchen, sie zu beantworten.
Jonathan Miles
es hat mir geholfen und meine Zeit gespart.
Ajay Malhotra