Как зациклить и визуализировать элементы в React.js без массива объектов для сопоставления?


146

Я пытаюсь преобразовать компонент jQuery в React.js, и одна из проблем, с которыми я сталкиваюсь, это рендеринг n элементов на основе цикла for.

Я понимаю, что это невозможно, или рекомендуется, и что, когда в модели существует массив, имеет смысл использовать его полностью map. Это нормально, но что делать, когда у вас нет массива? Вместо этого у вас есть числовое значение, которое соответствует заданному количеству элементов для рендеринга, тогда что вам следует делать?

Вот мой пример, я хочу добавить к элементу произвольное количество тегов span, основываясь на его иерархическом уровне. Итак, на уровне 3, я хочу 3 тега span перед текстовым элементом.

В JavaScript:

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

Кажется, я не могу этого понять или что-то похожее на работу в компоненте JSX React.js. Вместо этого мне пришлось сделать следующее: сначала создать временный массив правильной длины, а затем зациклить массив.

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

Конечно, это не может быть лучшим или единственным способом достичь этого? Чего мне не хватает?



Также вы можете просто сделать это: jsfiddle.net/crl/69z2wepo/19804
— caub

Ответы:


242

Обновлено: на момент реакции> 0,16

Метод рендеринга не обязательно должен возвращать один элемент. Массив также может быть возвращен.

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

ИЛИ

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

Документы здесь объясняют о детях JSX


OLD:

Вы можете использовать один цикл вместо

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

Вы также можете использовать .map и Fancy ES6

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

Кроме того, вы должны обернуть возвращаемое значение в контейнер. Я использовал div в приведенном выше примере

Как говорят здесь документы

В настоящее время при рендеринге компонента вы можете вернуть только один узел; если у вас есть, скажем, список возвращаемых элементов div, вы должны заключить компоненты в элемент div, span или любой другой компонент.


1
Это работает, и это намного проще, спасибо. Да, я знаю, что вы должны обернуть возвращаемое значение в контейнер, я уже делаю, что это просто отсутствует в примере.
— Джонатан Майлз

2
добавить ключи внутри цикла. ключи важны в реакции.
— Амир Африди

4
я искал тебя всю свою жизнь
— olleh

2
@ElgsQianChen Это невозможно. Он должен быть завернут в какой-то тег. Если {indents} возвращает один элемент dom с содержимым внутри, то все в порядке
— Dhiraj

2
Я не понимаю, почему метод map упоминается в этом ответе, поскольку он работает только для объектов Array, что, как ясно указывает вопрос, не соответствует действительности.
— flukyspore

47

Вот более функциональный пример с некоторыми функциями 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
Это выглядит как самый «Reacty» способ сделать это. Передать значения в качестве реквизита для другого подкомпонента. Спасибо!
— Майкл Джованни Пумо

Это здорово! Идеально подходит для случаев, когда ваш render () тяжелый HTML.
— Матфея

Чтобы сделать его более ES6, вы можете использовать import React from "react"иexport default Articles
— jonlink

1
Этот ответ даже не пытается ответить на вопрос. Был ясен вопрос, как преобразовать a for loopв массив (или объект) map'able, чтобы визуализировать n элементов в компоненте React, не имея массива элементов. Ваше решение полностью игнорирует этот факт и предполагает передачу массива статей из реквизита.
— Джонатан Майлз

17

Я использую Object.keys(chars).map(...)цикл в рендере

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

Ваш ответ сработал для меня, но только после того, как я добавил chars && ...и .bind(this)в конце моей функции. Мне любопытно, почему просто Object...(так далее и так далее) не работало. Я продолжал становиться неопределенным.
— m00saca

2
Это не отвечает на вопрос, в частности, говорится, что для анализа не требуется массив объектов, а в объяснении явно говорится, что я хочу преобразовать цикл for в карту для рендеринга в компоненте React. Вы заменили массив объектом, который не помогает ответить на вопрос, или добавили какое-либо дополнительное значение.
— Джонатан Майлз

16

Array.from()принимает итеративный объект для преобразования в массив и дополнительную функцию карты. Вы можете создать объект со .lengthсвойством следующим образом:

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

Я случайно увидел твой вопрос после прослушивания на прошлой неделе, так что это был самый быстрый способ применить то, что я узнал! syntax.fm/show/043/…
— conradj

1
Как раз то, что мне нужно для рендеринга количества элементов X, спасибо!
— Лиран Х,

0

Я думаю, что это самый простой способ прореагировать на JS

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

2
Это не отвечает на вопрос, пожалуйста, прочитайте вопрос полностью, прежде чем пытаться ответить.
— Джонатан Майлз

это помогло мне и сэкономило мое время.
— Аджай Малхотра
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.