Comment boucler et rendre des éléments dans React.js sans un tableau d'objets à mapper?

146

J'essaie de convertir un composant jQuery en React.js et l'une des choses avec lesquelles j'ai du mal est de rendre n nombre d'éléments basés sur une boucle for.

Je comprends que ce n'est pas possible ou recommandé et que lorsqu'un tableau existe dans le modèle, il est parfaitement logique de l'utiliser map. C'est bien, mais qu'en est-il lorsque vous n'avez pas de tableau? Au lieu de cela, vous avez une valeur numérique qui équivaut à un nombre donné d'éléments à rendre, alors que devez-vous faire?

Voici mon exemple, je veux préfixer un élément avec un nombre arbitraire de balises span en fonction de son niveau hiérarchique. Donc au niveau 3, je veux 3 balises span avant l'élément de texte.

En javascript:

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

Je n'arrive pas à comprendre cela, ou quelque chose de similaire pour travailler dans un composant JSX React.js. Au lieu de cela, j'ai dû faire ce qui suit, en construisant d'abord un tableau temporaire à la longueur correcte, puis en bouclant le tableau.

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

Cela ne peut certainement pas être le meilleur ou le seul moyen d'y parvenir? Qu'est-ce que je rate?

Jonathan Miles
la source
aussi vous pouvez simplement le faire: jsfiddle.net/crl/69z2wepo/19804
caub

Réponses:

242

Mise à jour: à partir de React> 0,16

La méthode de rendu ne doit pas nécessairement renvoyer un seul élément. Un tableau peut également être renvoyé.

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

OU

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

Docs ici expliquant les enfants JSX


VIEUX:

Vous pouvez utiliser une boucle à la place

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

Vous pouvez également utiliser .map et fancy es6

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

En outre, vous devez envelopper la valeur de retour dans un conteneur. J'ai utilisé div dans l'exemple ci-dessus

Comme le disent les documents ici

Actuellement, dans le rendu d'un composant, vous ne pouvez renvoyer qu'un seul nœud; si vous avez, par exemple, une liste de div à renvoyer, vous devez envelopper vos composants dans un div, un span ou tout autre composant.

Dhiraj
la source
1
Cela fonctionne, et c'est beaucoup plus simple merci. Oui, je suis conscient que vous devez envelopper la valeur de retour dans le conteneur, je le fais déjà, il manque juste de l'exemple.
Jonathan Miles
2
ajoutez des clés à l'intérieur de la boucle. les clés sont importantes pour réagir.
Aamir Afridi
4
Je t'ai cherché toute ma vie
olleh
2
@ElgsQianChen Ce n'est pas possible. Il doit être emballé avec une étiquette. Si {indents} renvoie un seul élément dom avec du contenu à l'intérieur, alors c'est ok
Dhiraj
2
Je ne comprends pas pourquoi la méthode map est mentionnée dans cette réponse, car elle ne fonctionne que pour les objets Array, ce que la question indique clairement n'est pas le cas.
flukyspore
47

Voici un exemple plus fonctionnel avec quelques fonctionnalités 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;
Dmytro Medvid
la source
1
Cela ressemble à la façon la plus «réactive» de le faire. Transmettez les valeurs comme accessoires à un autre sous-composant. Merci!
Michael Giovanni Pumo
C'est génial! Parfait lorsque votre render () est lourd en HTML.
matthew
Pour le rendre plus ES6, vous pouvez utiliser import React from "react"etexport default Articles
jonlink
1
Cette réponse n'essaye même pas de répondre à la question. La question était claire, comment convertir un for loopen un tableau (ou un objet) map'able afin de restituer n nombre d'éléments dans un composant React sans avoir un tableau d'éléments. Votre solution ignore complètement ce fait et suppose que vous avez passé un tableau d'articles à partir d'accessoires.
Jonathan Miles
17

J'utilise Object.keys(chars).map(...)pour faire une boucle dans le rendu

// 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
la source
Votre réponse a fonctionné pour moi, mais seulement après avoir ajouté chars && ...et .bind(this)à la fin de ma fonction. Je suis curieux de savoir pourquoi tout simplement Object...(et ainsi de suite) n'a pas fonctionné. J'ai continué à être indéfini.
m00saca
2
Cela ne répond pas à la question, il dit spécifiquement sans tableau d'objets à analyser et l'explication dit explicitement que je veux convertir une boucle for en mappage pour le rendu dans un composant React. Vous avez substitué un tableau à un objet qui n'aide pas à répondre à la question ou à ajouter une valeur supplémentaire.
Jonathan Miles
16

Array.from()prend un objet itérable à convertir en un tableau et une fonction de carte facultative. Vous pouvez créer un objet avec une .lengthpropriété comme suit:

return Array.from({length: this.props.level}, (item, index) => 
  <span className="indent" key={index}></span>
);
conradj
la source
Je viens de voir votre question après l'avoir écoutée la semaine dernière, donc c'était le moyen le plus rapide d'appliquer ce que j'avais appris! syntax.fm/show/043/…
conradj
1
Juste ce dont j'avais besoin pour rendre X nombre d'éléments, merci!
Liran H
0

Je pense que c'est le moyen le plus simple de faire une boucle dans react js

<ul>
    {yourarray.map((item)=><li>{item}</li>)}
</ul>
Nasar uddin
la source
2
Cela ne répond pas à la question, veuillez lire la question en entier avant d'essayer de répondre.
Jonathan Miles
cela m'a aidé et m'a fait gagner du temps.
Ajay Malhotra