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