Jak zapętlić i renderować elementy w React.js bez tablicy obiektów do zmapowania?

145

Próbuję przekonwertować składnik jQuery do React.js i jedną z rzeczy, z którymi mam problem, jest renderowanie n liczby elementów w oparciu o pętlę for.

Rozumiem, że nie jest to możliwe lub zalecane, a jeśli w modelu istnieje tablica, jej użycie ma sens map. W porządku, ale co, jeśli nie masz tablicy? Zamiast tego masz wartość liczbową, która jest równa określonej liczbie elementów do renderowania, więc co powinieneś zrobić?

Oto mój przykład, chcę poprzedzić element dowolną liczbą tagów span w oparciu o jego poziom hierarchiczny. Tak więc na poziomie 3 chcę 3 znaczniki span przed elementem tekstowym.

W javascript:

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

Nie mogę uzyskać tego ani niczego podobnego do pracy w komponencie JSX React.js. Zamiast tego musiałem wykonać następujące czynności, najpierw zbudować tablicę tymczasową o odpowiedniej długości, a następnie zapętlić tablicę.

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

Z pewnością nie może to być najlepszy lub jedyny sposób na osiągnięcie tego? czego mi brakuje?

Jonathan Miles
źródło
możesz też po prostu to zrobić: jsfiddle.net/crl/69z2wepo/19804
caub

Odpowiedzi:

241

Zaktualizowano: od React> 0.16

Metoda Render niekoniecznie musi zwracać pojedynczy element. Można również zwrócić tablicę.

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

LUB

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

Dokumenty wyjaśniające dzieci JSX


STARY:

Zamiast tego możesz użyć jednej pętli

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

Możesz także użyć .map i fantazyjnego es6

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

Musisz także opakować zwracaną wartość w kontenerze. W powyższym przykładzie użyłem div

Jak mówią tutaj doktorzy

Obecnie podczas renderowania komponentu można zwrócić tylko jeden węzeł; jeśli masz, powiedzmy, listę elementów div do zwrócenia, musisz opakować komponenty w element div, span lub inny składnik.

Dhiraj
źródło
1
To działa i dzięki temu jest o wiele prostsze. Tak, zdaję sobie sprawę, że musisz zawijać wartość zwracaną w kontenerze, robię to już tego po prostu brakuje w przykładzie.
Jonathan Miles
2
dodaj klucze wewnątrz pętli. Klucze są ważne w reakcji.
Aamir Afridi
4
Szukałem cię przez całe życie
olleh
2
@ElgsQianChen To niemożliwe. Musi być owinięty jakąś metką. Jeśli {indents} zwraca pojedynczy element dom z zawartością w środku, to jest w porządku
Dhiraj
2
Nie rozumiem, dlaczego w tej odpowiedzi jest mowa o metodzie map, ponieważ działa ona tylko dla obiektów Array, o czym wyraźnie wynika, że ​​nie jest to przypadek.
flukyspore
47

Oto bardziej funkcjonalny przykład z niektórymi funkcjami 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
źródło
1
To wygląda na najbardziej reaktywny sposób na zrobienie tego. Przekaż wartości jako rekwizyty do innego komponentu podrzędnego. Dzięki!
Michael Giovanni Pumo
To wspaniale! Idealne, gdy render () jest ciężki w HTML.
Matthew
Aby uczynić go bardziej ES6, możesz użyć import React from "react"iexport default Articles
jonlink
1
Ta odpowiedź nawet nie próbuje odpowiedzieć na pytanie. Pytanie było jasne, jak przekonwertować a for loopna tablicę (lub obiekt) możliwą do mapowania, aby wyrenderować liczbę n elementów w komponencie React bez posiadania tablicy elementów. Twoje rozwiązanie całkowicie ignoruje ten fakt i zakłada przekazanie szeregu artykułów z rekwizytów.
Jonathan Miles,
17

Używam Object.keys(chars).map(...)do zapętlenia w renderowaniu

// 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
źródło
Twoja odpowiedź zadziałała dla mnie, ale dopiero po dodaniu chars && ...i .bind(this)na końcu mojej funkcji. Jestem ciekawy, dlaczego po prostu Object...(tak dalej i tak dalej) nie zadziałało. Ciągle byłem niezdefiniowany.
m00saca
2
To nie odpowiada na pytanie, konkretnie mówi, że nie ma tablicy obiektów do przeanalizowania, a wyjaśnienie wyraźnie mówi, że chcę przekonwertować pętlę for na mapę do renderowania w komponencie React. Zastąpiłeś tablicę obiektem, który nie pomaga odpowiedzieć na pytanie ani nie dodaje żadnej dalszej wartości.
Jonathan Miles,
16

Array.from()pobiera iterowalny obiekt do konwersji na tablicę i opcjonalną funkcję mapy. Możesz utworzyć obiekt z .lengthwłaściwością w następujący sposób:

return Array.from({length: this.props.level}, (item, index) => 
  <span className="indent" key={index}></span>
);
conradj
źródło
Po prostu przypadkiem zobaczyłem twoje pytanie po wysłuchaniu tego w zeszłym tygodniu, więc był to najszybszy sposób na zastosowanie tego, czego się nauczyłem! syntax.fm/show/043/…
conradj
1
Właśnie tego potrzebowałem do renderowania X elementów, dziękuję!
Liran H
0

Myślę, że jest to najłatwiejszy sposób na zapętlenie reakcji js

<ul>
    {yourarray.map((item)=><li>{item}</li>)}
</ul>
Nasar uddin
źródło
2
To nie jest odpowiedzią na pytanie. Przed podjęciem próby udzielenia odpowiedzi przeczytaj je w całości.
Jonathan Miles,
pomogło mi i zaoszczędziło mi czasu.
Ajay Malhotra