Jak renderować elementy rodzeństwa bez zawijania ich w tagu nadrzędnym?

82

W większości przypadków posiadanie tagu nadrzędnego nie stanowi problemu.

React.createClass({
    render: function() {
        return (
            <tbody>
                <tr><td>Item 1</td></tr>
                <tr><td>Item 2</td></tr>
            </tbody>
        );
    }
});

Ale są pewne przypadki, w których ma sens posiadanie elementów rodzeństwa w jednej funkcji renderującej bez rodzica, a zwłaszcza w przypadku tabeli, nie chcesz zawijać wiersza tabeli w a div.

React.createClass({
    render: function() {
        return (
            <tr><td>Item 1</td></tr>
            <tr><td>Item 2</td></tr>
        );
    }
});

Drugi przykład daje następujący błąd: Adjacent XJS elements must be wrapped in an enclosing tag while parsing file.

Jak mogę wyrenderować dwa elementy rodzeństwa bez zawijania ich w <div>coś podobnego?

thealexbaron
źródło
3
Zawsze wydaje mi się, że mam problem ze znalezieniem tego pytania / odpowiedzi, więc postanowiłem zadać / odpowiedzieć samodzielnie. Dodatkowe wyjaśnienia / odpowiedzi są mile widziane.
thealexbaron
Innym przykładem są elementy nawigacyjne
Tjorriemorrie

Odpowiedzi:

66

Jest to obecnie ograniczenie, ale prawdopodobnie zostanie naprawione w przyszłości ( w repozytorium github są otwarte problemy ).

Na razie możesz użyć funkcji, która zwraca tablicę (jest to w zasadzie składnik bezstanowy):

function things(arg, onWhatever){
    return [
        <tr><td>Item 1</td></tr>,
        <tr><td>Item 2</td></tr>
    ];
}

I użyj tego w swoim komponencie.

return (
    <table><tbody>
      {things(arg1, this.handleWhatever)}
      {things(arg2, this.handleWhatever)}
    </tbody></table>
);

Aktualizacja

W Reakcie 16 będziesz mógł zwrócić tablicę z renderowania.

Kolejna aktualizacja

Możesz teraz zwrócić tablicę najwyższego poziomu lub użyć <React.Fragment>.

W przypadku tablicy musimy umieścić klucz na każdym elemencie, ponieważ React nie wie, że te dwa elementy są stałe, zamiast dynamicznie tworzonej listy:

function RowPair() {
  return [
    <tr key="first"><td>First</td></tr>,
    <tr key="second"><td>Second</td></tr>,
  ]
}

Z React.Fragmentzachowuje się znacznie bardziej jak zawijanie go w coś <div>podobnego, gdzie keynie jest wymagane, jeśli nie budujemy dzieci dynamicznie. Najpierw możemy zawinąć tablicę we fragment:

function RowPair() {
  return <React.Fragment>{[
    <tr key="first"><td>First</td></tr>,
    <tr key="second"><td>Second</td></tr>,
  ]}</React.Fragment>
}

Następnie możemy keycałkowicie wyeliminować tablicę is:

function RowPair() {
  return <React.Fragment>
    <tr><td>First</td></tr>
    <tr><td>Second</td></tr>
  </React.Fragment>
}
Bandyta
źródło
2
Dlaczego wszyscy mówią, że to działa ???? Uncaught Error: x.render (): Należy zwrócić prawidłowy element React (lub wartość null). Mogłeś zwrócić undefined, tablicę lub inny nieprawidłowy obiekt.
Xogle
@Xogle Coś musiało się zmienić w interfejsie React API. Wydaje się, że już nie działa.
Petr Peller
1
@FakeRainBrigand Widzę problem. To nie jest „składnik bezstanowy”, to funkcja zwracająca tablicę. Komponenty bezstanowe nie mogą zwracać tablic i nie można podłączyć prostej funkcji do sklepu Redux.
Petr Peller,
@PetrPeller czy używasz jsx? W przykładzie nazywam to funkcją.
Brigand
Nie rozumiem wszystkich pozytywnych głosów - to w ogóle nie odpowiada na pytanie. Pytanie brzmi, jak renderować elementy rodzicielskie bez elementu nadrzędnego, a ta odpowiedź nadal renderuje element nadrzędny.
Dancrumb
33

Wiem, że to był stary post, ale może moja odpowiedź byłaby pomocna dla początkujących, takich jak ja.

W Reakcie 16.2 dodano ulepszoną obsługę fragmentów .

Możesz teraz zwrócić go w ten sposób:

return (
  <>
    <tr><td>Item 1</td></tr>
    <tr><td>Item 2</td></tr>
  </>
);

Możesz go owinąć <></>lub <Fragment></Fragment>.

Jeśli chcesz przekazać niektóre atrybuty, tylko klucz jest obsługiwany w momencie pisania i będziesz musiał go użyć, <Fragment />ponieważ krótka składnia <></>nie akceptuje atrybutów.

Uwaga: jeśli zamierzasz używać krótkiej składni, upewnij się, że używasz Babel 7 .

Źródło odniesienia

onoya
źródło
1
Dokładnie to, o co mi chodziło, dzięki! Poza tym, na wypadek, gdyby ktoś tego potrzebował: zaimportuj Reacta, {Fragment} z „reaguj”
Chris,
Nie mogę znaleźć implementacji Fragmentw ich repozytorium, czy ktoś może mi pokazać? Dzięki :)
Ramon Balthazar
Nie mogę sprawić, żeby to zadziałało, nawet jeśli zainstaluję Babel-cli ... nawet tylko dla rozwiązania <>. Jak to możliwe @onoya Wkrótce opublikuję wątek,
Gaelle
3

Posiadanie elementu nadrzędnego jest pomocne w większości przypadków, na przykład możesz mieć nadrzędną nazwę klasy, która może być ukierunkowana na styl elementów podrzędnych i kilka innych scenariuszy ...

Ale jeśli naprawdę nie chcesz tego robić, możesz użyć React.Fragment

Więc po prostu zrób coś takiego:

<React.Fragment>
  <First />
  <Second />
  <Third />
</React.Fragment>

Od wersji 16.2 dostępna jest także skrócona wersja <>, która w funkcji renderowania wygląda tak:

render() {
  return (
    <>
      <First />
      <Second />
      <Third />
    </>
  );
}

Ponadto, jeśli używasz wersji 16.0 i nowszych, możesz zwrócić tablicę elementów, które nie wymagają opakowania nadrzędnego, tak jak poniżej:

render() {
 return [
  <h1 key="heading">Hello from Alireza!</h1>,
  <p key="first">Here where I'm!</p>,
  <p key="second">And again here :)</p>
 ];
}
Alireza
źródło
0

Możesz owinąć go w nawiasy w ten sposób:

React.createClass({
    render: function() {
        return (
          [
            <tr><td>Item 1</td></tr>
            <tr><td>Item 2</td></tr>
          ]
        );
    }
});
Vitaliy Andrusishyn
źródło
Co powiesz na to, że musisz również użyć Object.keys()w ramach zwrotu?
Juha Untinen
Na przykład. return ( [ <tr><td>Header</td></tr>{ Object.keys(this.props.data).map(function(item) { <tr><td>{data}</td></tr> }) } ] ); W 15.4.2 daje Unexpected token, expected ,w nawiasie otwierającym w rewanżu
Juha Untinen
spróbuj czegoś takiego: return ({Object.keys (this.props.data) .map (function (item) {<tr><td>{data}</td> </tr>}). unshift ({< tr> <td> Nagłówek </td> </tr>})});
Vitaliy Andrusishyn
To nie działa, nadal trzeba mieć przecinek oddzielający <tr> -s
Philipp Munin
0

Ten przykład działa dobrze dla mnie:

let values = [];

if (props.Values){
  values = [
    <tr key={1}>
      <td>props.Values[0].SomeValue</td>
    </tr>
  ,
    <tr key={2}>
        <td>props.Values[1].SomeValue</td>
        </tr>
    ];
}

return (
    <table className="no-border-table table">
      <tbody>
        <tr>
            <th>Some text</th>
        </tr>
        {values}
      </tbody>
    </table>
)
MrDuDuDu
źródło
0

Coś takiego jak ta składnia zadziałało dla mnie

this.props.map((data,index)=>{return( [ <tr>....</tr>,<tr>....</tr>];)});
Superve
źródło
-2

Dla tych, którzy używają TypeScript, prawidłowa składnia to:

return [
  (
    <div>Foo</div>
  ),
  (
    <div>Bar</div>
  )
];
0leg
źródło
1
Jest to identyczne z odpowiedzią @thealexbaron i nie ma to nic wspólnego z TypeScript
andrewarchi