Jak zwrócić wiele wierszy JSX w innej instrukcji return w Reakcie?

100

Pojedyncza linia działa dobrze

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

nie dla wielu linii

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

Dzięki.

Shawn
źródło
1
Więcej informacji na temat tego konkretnego wydania: github.com/facebook/react/issues/2127
plus-
nie return ("asdf" "asdf");chceszreturn ["asdf", "asdf"];
neaumusic

Odpowiedzi:

149

Spróbuj myśleć o tagach jako o wywołaniach funkcji (zobacz dokumentację ). Wtedy pierwszy staje się:

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

A drugi:

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

Powinno być teraz jasne, że drugi fragment kodu tak naprawdę nie ma sensu (nie możesz zwrócić więcej niż jednej wartości w JS). Musisz albo zawinąć go w inny element (najprawdopodobniej to, co chcesz, w ten sposób możesz również podać prawidłową keywłaściwość) lub możesz użyć czegoś takiego:

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

Z cukrem JSX:

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

Nie musisz spłaszczać wynikowej tablicy, React zrobi to za Ciebie. Zobacz następujące skrzypce http://jsfiddle.net/mEB2V/1/ . Ponownie: zawinięcie dwóch elementów w div / section będzie najprawdopodobniej lepsze na dłuższą metę.

Jan Olaf Krems
źródło
4
Tak, faktycznie wyraźnie udokumentowane facebook.github.io/react/tips/ ...
Shawn,
1
Użycie funkcji return ([...]) bez spłaszczonego bitu daje mi znaczniki dokładnie tak, jak chciałem, chociaż zwrócona tablica nie może być spłaszczona, ale w moim przypadku nie ma to wpływu na ostateczne wyjście. Albo to jest?
Shawn
Dzięki! TIL! Aktualizacja mojej odpowiedzi, aby zawierała łącze do JSFiddle, które pokazuje, że spłaszczenie jest opcjonalne. Będzie również zawierać link do dokumentów React.
Jan Olaf Krems
13
To już nie działa (od 0,9)Uncaught Error: Invariant Violation: Product.render(): A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object.
dogmatyczne69
2
@TimFletcher Dobrze jest zwrócić tablicę jako część renderowania komponentu, np <div>{ this.props.foos.map(function() { return <Foo /> }) }</div>. Ale renderfunkcja komponentu nie może zwrócić tej tablicy bez jej opakowania, np. W div.
Henrik N,
35

Wygląda na to, że stara odpowiedź dotycząca zwracania tablicy już nie ma zastosowania (może od czasu React ~ 0.9, jak @ dogmatic69 napisał w komentarzu ).

Dokumenty mówią, że musisz zwrócić pojedynczy węzeł:

Maksymalna liczba węzłów głównych JSX

Obecnie w renderowaniu komponentu można zwrócić tylko jeden węzeł; jeśli masz, powiedzmy, listę elementów div do zwrócenia, musisz umieścić swoje komponenty w elemencie div, span lub innym elemencie.

Nie zapominaj, że JSX kompiluje się do zwykłego JS; zwracanie dwóch funkcji tak naprawdę nie ma sensu składniowego. Podobnie, nie umieszczaj więcej niż jednego dziecka w trójce.

W wielu przypadkach możesz po prostu zawinąć rzeczy w plik a <div>lub a <span>.

W moim przypadku chciałem zwrócić wiele <tr>s. Owinąłem je w <tbody>- stół może mieć wiele ciał.

EDYCJA: Od React 16.0 zwracanie tablicy jest najwyraźniej znowu dozwolone, o ile każdy element ma key: https://facebook.github.io/react/blog/2017/09/26/react-v16.0.html # new-render-return-types-fragments-and-strings

EDYCJA: React 16.2 pozwala otoczyć listę elementów tablicą <Fragment>…</Fragment>lub nawet <>…</>, jeśli wolisz, że: https://blog.jmes.tech/react-fragment-and-semantic-html/

Henrik N
źródło
3
Co możesz zrobić, jeśli chcesz zwrócić wiele <li>? Zakładając, że nie mogę po prostu tego wszystkiego <ul>
zawrzeć
@Banjocat Obawiam się, że nie wiem: / Możesz zagnieżdżać listy, więc możesz zwrócić coś takiego <li><ul><li>one</li><li>two</li></ul></li>, jak to działa w Twojej sytuacji. Lub: opakowujący element div nie byłby prawidłowy, ale może renderuje się dobrze we wszystkich odpowiednich przeglądarkach? Jeśli spróbujesz, daj nam znać.
Henrik N
1
@Banjocat ... Chciałbym poznać lepszą odpowiedź na Twoje pytanie. Może powinieneś zadać to pytanie jako zwykłe pytanie związane z przepełnieniem stosu i sprawdzić, czy otrzymasz inną odpowiedź.
user1175849
@ user1175849 Może pan mógłby odpowiedzieć na to pytanie, a następnie :)
Henrik N
1
@HenrikN Fwiw, zawijanie „podzbioru” liw a spanlub divnie działało dobrze dla mnie. Div poważnie zepsuł renderowanie i, przynajmniej w moim przypadku, rozpiętość zepsuła CSS. 2 ¢: Próba zwrócenia kilku podzbiorów lis to zapach kodu. Używaliśmy uljako swego rodzaju menu rozwijanego i początkowo chciałem, aby wiele komponentów zwracało „sekcje” lis. Ostatecznie lepiej było umieścić cały kod menu w jednym „zakotwiczonym” elemencie ulniż w łyżce do butów liz wielu źródeł. Myślę, że dzięki temu model mentalny interfejsu użytkownika stał się nieco czystszy.
ruffin
13

Począwszy od wersji 16.0.0 Reacta możliwe jest zwrócenie wielu elementów poprzez umieszczenie ich w plikuArray

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

Również w React 16.2.0 wprowadzono nową funkcję o nazwie, React Fragmentsktórej można użyć do zawijania wielu elementów

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

Zgodnie z dokumentacją:

Powszechnym wzorcem w Reakcie jest zwracanie przez komponent wielu elementów. Fragmenty umożliwiają grupowanie listy dzieci bez dodawania dodatkowych węzłów do DOM.

Fragmenty zadeklarowane przy użyciu jawnej składni mogą mieć klucze. Przykładem użycia jest mapowanie kolekcji na tablicę fragmentów - na przykład w celu utworzenia listy opisów:

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

klucz jest jedynym atrybutem, który można przekazać do fragmentu. W przyszłości możemy dodać obsługę dodatkowych atrybutów, takich jak programy obsługi zdarzeń.

Shubham Khatri
źródło
7

Możesz także chcieć zwrócić kilka elementów listy w jakiejś funkcji pomocniczej wewnątrz komponentu React. Po prostu zwróć tablicę węzłów html z keyatrybutem:

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>,
    ]
  }
}
Dmitriy
źródło
2

Możesz użyć createFragmenttutaj.

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

(używając tutaj składni ES6 i JSX)

najpierw musisz dodać react-addons-create-fragmentpakiet:

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

Przewaga nad rozwiązaniem Jana Olafa Kremsa: reaguj, nie narzekaj na zaginięcie key

sylvain
źródło
popraw mnie, jeśli się mylę, ale możesz po prostu dodać klucze ręcznie. używając przykładu jana: pierwszy element tablicy otrzymuje np. <h3 key = {i}> </h3>, a drugi element tablicy sth nieco inny, jak <p> key = {i + '-foo'}> </p>
nerdess
2

Zaktualizowano

Użyj fragmentu reakcji. To proste. Link do fragmentowej dokumentacji.

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

Stara odpowiedź - nieaktualna

W przypadku React> 16 możesz użyć kompozytu reagującego .

import { Composite } from 'react-composite';

// ...

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

Oczywiście należy zainstalować kompozyt reakcyjny.

npm install react-composite --save
Pan Br
źródło
0

Jest to proste przez fragment Reacta <></>i React.Fragment:

return (
    <>
      {[1, 2, 3].map(
        (n, index): ReactElement => (
          <React.Fragment key={index}>
            <h3>Item {n}</h3>
            <p>Description {n}</p>
          </React.Fragment>
        ),
      )}
    </>
  );
Masih Jahangiri
źródło