Как вернуть несколько строк JSX в другой оператор возврата в React?


100

Одна линия отлично работает

render: function () {
  return (
    {[1,2,3].map(function (n) {
      return <p>{n}</p>
    }}
  );
}

не для нескольких строк

render: function () {
  return (
    {[1,2,3].map(function (n) {
      return (
        <h3>Item {n}</h3>
        <p>Description {n}</p>
      )
    }}
  );
}

Спасибо.


1
Для получения дополнительной информации по этому конкретному вопросу: github.com/facebook/react/issues/2127
— плюс -

не return ("asdf" "asdf");вы хотитеreturn ["asdf", "asdf"];
— neaumusic

Ответы:


149

Попробуйте представить теги как вызовы функций (см. Документацию ). Тогда первый становится:

{[1,2,3].map(function (n) {
  return React.DOM.p(...);
})}

И второй:

{[1,2,3].map(function (n) {
  return (
    React.DOM.h3(...)
    React.DOM.p(...)
  )
})}

Теперь должно быть ясно, что второй фрагмент на самом деле не имеет смысла (вы не можете вернуть более одного значения в JS). Вам нужно либо обернуть его в другой элемент (скорее всего, то, что вы хотите, таким образом вы также можете предоставить допустимое keyсвойство), либо вы можете использовать что-то вроде этого:

{[1,2,3].map(function (n) {
  return ([
    React.DOM.h3(...),
    React.DOM.p(...)
  ]);
})}

С сахаром JSX:

{[1,2,3].map(function (n) {
  return ([
    <h3></h3>, // note the comma
    <p></p>
  ]);
})}

Вам не нужно сглаживать полученный массив, React сделает это за вас. См. Следующую скрипку http://jsfiddle.net/mEB2V/1/ . Опять же: объединение двух элементов в div / section, скорее всего, будет лучше в долгосрочной перспективе.


4
Да, на самом деле четко задокументировано facebook.github.io/react/tips/…
— Шон

1
Использование return ([...]) без бита сглаживания дает мне разметку в точности так, как я хотел, хотя возвращенный массив не должен был быть плоским, но в моем конкретном случае это не влияет на окончательный результат. Либо это?
— Шон

Спасибо! ТИЛЬ! Обновляю свой ответ, чтобы включить ссылку на JSFiddle, которая показывает, что flatten не является обязательным. Также будет включена ссылка на документы React.
— Ян Олаф Кремс

13
Это больше не работает (по состоянию на 0.9ish)Uncaught Error: Invariant Violation: Product.render(): A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object.
— dogmatic69

2
@TimFletcher. Можно вернуть массив как часть отрисовки компонента, например <div>{ this.props.foos.map(function() { return <Foo /> }) }</div>. Но renderфункция компонента не может вернуть этот массив, не обернув его, например, в div.
— Henrik N

35

Похоже, старый ответ о возврате массива больше не применяется (возможно, с React ~ 0.9, как написал @ dogmatic69 в комментарии ).

В документах говорится, что вам нужно вернуть один узел:

Максимальное количество корневых узлов JSX

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

Не забывайте, что JSX компилируется в обычный JS; возврат двух функций не имеет синтаксического смысла. Точно так же не помещайте более одного ребенка в тройку.

Во многих случаях вы можете просто заключить вещи в a <div>или a <span>.

В моем случае я хотел вернуть несколько <tr>s. Я завернул их в <tbody>- стол может иметь несколько тел.

РЕДАКТИРОВАТЬ: Начиная с React 16.0, возвращение массива, по-видимому, снова разрешено, если каждый элемент имеет key: https://facebook.github.io/react/blog/2017/09/26/react-v16.0.html # new-render-return-types-fragments-and-strings

РЕДАКТИРОВАТЬ: React 16.2 позволяет окружать список элементов <Fragment>…</Fragment>или даже <>…</>, если вы предпочитаете это массивом: https://blog.jmes.tech/react-fragment-and-semantic-html/


3
Что вы можете сделать, если хотите вернуть несколько <li>? Предполагая, что я не могу просто обернуть все это<ul>
— Банджокат

@Banjocat Боюсь , я не знаю: / Вы имеете право гнездовых списки, чтобы вы могли вернуть что - то вроде <li><ul><li>one</li><li>two</li></ul></li>, что работает в вашей ситуации. Или: обертывающий div не будет строго допустимым, но, возможно, он отлично отображается во всех соответствующих браузерах? Если попробуете, дайте нам знать.
— Henrik N

1
@Banjocat ... Мне бы хотелось узнать ответ на твой вопрос получше. Может быть, вам стоит сформулировать это как обычный вопрос о стеке и посмотреть, получите ли вы другой ответ.
— user1175849

@ user1175849 Может быть, тогда вы могли бы опубликовать этот вопрос :)
— Henrik N

1
@HenrikN Fwiw, обертывание "подмножества" liв a spanили divне сработало для меня. Div серьезно нарушил рендеринг, и, по крайней мере, в моем случае использования span испортил CSS. 2 ¢: Попытка вернуть несколько подмножеств lis - это запах кода. Мы использовали a ulкак своего рода выпадающее меню, и я изначально хотел, чтобы многие компоненты возвращали «разделы» lis. В конце концов, было лучше поместить весь код меню в один компонент, «привязанный» к нему, ulчем вставлять элементы liиз нескольких источников. Я думаю, что это также сделало ментальную модель пользовательского интерфейса немного чище.
— ruffin

13

Начиная с React v16.0.0 и далее, можно возвращать несколько элементов, заключая их вArray

render() {
  return (
    {[1,2,3].map(function (n) {
      return [
        <h3>Item {n}</h3>.
        <p>Description {n}</p>
      ]
    }}
  );
}

Также в React v16.2.0 представлена ​​новая функция, React Fragmentsкоторую вы можете использовать для переноса нескольких элементов.

render() {
  return (
    {[1,2,3].map(function (n, index) {
      return (
        <React.Fragment key={index}>
            <h3>Item {n}</h3>
            <p>Description {n}</p>
        </React.Fragment>
      )
    }}
  );
}

Согласно документации:

Распространенный шаблон в React - компонент, возвращающий несколько элементов. Фрагменты позволяют группировать список дочерних элементов без добавления дополнительных узлов в DOM.

Фрагменты, объявленные с явным синтаксисом, могут иметь ключи. Пример использования для этого - сопоставление коллекции с массивом фрагментов - например, для создания списка описания:

function Glossary(props) {
  return (
    <dl>
      {props.items.map(item => (
        // Without the `key`, React will fire a key warning
        <React.Fragment key={item.id}>
          <dt>{item.term}</dt>
          <dd>{item.description}</dd>
        </React.Fragment>
      ))}
    </dl>
  );
}

key - единственный атрибут, который можно передать Fragment. В будущем мы можем добавить поддержку дополнительных атрибутов, таких как обработчики событий.


7

Кроме того, вы можете захотеть вернуть несколько элементов списка в некоторой вспомогательной функции внутри компонента React. Просто верните массив узлов html с keyатрибутом:

import React, { Component } from 'react'

class YourComponent extends Component {
  // ...

  render() {
    return (
      <ul>
        {this.renderListItems()}
      </ul>
    )
  }      

  renderListItems() {
    return [
      <li key={1}><a href="#">Link1</a></li>,
      <li key={2}><a href="#">Link2</a></li>,
      <li key={3} className="active">Active item</li>,
    ]
  }
}

2

Вы можете использовать createFragmentздесь.

https://facebook.github.io/react/docs/create-fragment.html

import createFragment from 'react-addons-create-fragment';
...
{[1,2,3].map((n) => createFragment({
    h: <h3>...</h3>,
    p: <p>...</p>
  })
)}

(здесь используется синтаксис ES6 и JSX)

вам сначала нужно добавить react-addons-create-fragmentпакет:

npm install --save react-addons-create-fragment

Преимущество перед решением Яна Олафа Кремса: React не жалуется на отсутствие key


поправьте меня, если я ошибаюсь, но вы можете просто добавить ключи вручную. используя пример Яна: первый элемент массива получает, например, <h3 key = {i}> </h3>, а второй элемент массива sth немного отличается, например, <p> key = {i + '-foo'}> </p>
— nerdess

2

Обновлено

Используйте React Fragment. Это просто. Ссылка на фрагмент документации.

render() {
  return (
    <>
    {[1,2,3].map((value) => <div>{value}</div>)}
    </>
  );
}

Старый ответ - устаревший

С React> 16 вы можете использовать react-Composite .

import { Composite } from 'react-composite';

// ...

{[1,2,3].map((n) => (
  <Composite>
    <h2>Title {n}</h2>
    <p>Description {n}</p>
  </Composite>
))};

Конечно, необходимо установить реакт-композит.

npm install react-composite --save

0

Это просто по фрагменту React <></>и React.Fragment:

return (
    <>
      {[1, 2, 3].map(
        (n, index): ReactElement => (
          <React.Fragment key={index}>
            <h3>Item {n}</h3>
            <p>Description {n}</p>
          </React.Fragment>
        ),
      )}
    </>
  );
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.