Як повернути кілька рядків 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
плюс -

not return ("asdf" "asdf");you wantreturn ["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, яке показує, що сплюстити необов’язково. Також міститиме посилання на документи 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.
Генрік Н

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

EDIT: 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 не буде строго дійсним, але, можливо, він чудово відображається у всіх відповідних браузерах? Якщо ви спробуєте, повідомте нас.
Генрік Н

1
@Banjocat ... Я хотів би знати кращу відповідь на ваше запитання. Можливо, вам слід поставити його як звичайне запитання про стек-потік і подивитися, чи отримаєте ви іншу відповідь.
user1175849

@ user1175849 Можливо, ви могли б опублікувати це запитання :)
Генрік Н

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

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

ключ - єдиний атрибут, який можна передати фрагменту. У майбутньому ми можемо додати підтримку для додаткових атрибутів, таких як обробники подій.


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

Перевага над рішенням Яна Олафа Кремса: реакція не скаржиться на зниклих key


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

2

Оновлено

Використовуйте фрагмент реагування. Це просто. Посилання на документацію фрагментів.

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

Стара відповідь - застаріла

При React> 16 ви можете використовувати реакційноздатний композит .

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.