Як зробити віртуальні елементи, не обертаючи їх батьківським тегом?


82

У більшості випадків наявність батьківського тегу не є проблемою.

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

Але є деякі випадки, коли має сенс мати елементи односемейного зв'язку в одній функції візуалізації без батьківського елемента, і особливо у випадку таблиці, ви не хочете обертати рядок таблиці в div.

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

Другий приклад дає наступне повідомлення про помилку: Adjacent XJS elements must be wrapped in an enclosing tag while parsing file.

Як я можу відтворити два елементи брата або сестри, не загортаючи їх у <div>чи щось подібне?


3
Мені здається, завжди виникають проблеми з пошуком цього запитання / відповіді, тому я вирішив сам запитати / відповісти на нього. Додаткові пояснення / відповіді вітаються.
thealexbaron

Інший приклад - навігаційні предмети
Tjorriemorrie

Відповіді:


66

Наразі це обмеження, але, ймовірно, це буде виправлено в якийсь момент у майбутньому ( у репозиторії github є деякі відкриті проблеми ).

Наразі ви можете використовувати функцію, яка повертає масив (це в основному компонент без стану):

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

І використовуйте це у своєму компоненті.

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

Оновлення

У React 16 ви зможете повернути масив із візуалізації.

Ще одне оновлення

Тепер ви можете або повернути масив верхнього рівня, або використовувати <React.Fragment>.

За допомогою масиву нам потрібно розмістити ключ на кожному елементі, оскільки React не знає, що два елементи є постійними, замість динамічно створеного списку:

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

З React.Fragment, він поводиться набагато більше, як обгортання його в <div>або подібне, де a keyне потрібно, якщо ми не будуємо дітей динамічно. Спочатку ми можемо обернути масив у фрагмент:

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

І тоді ми можемо повністю усунути масив і keys:

function RowPair() {
  return <React.Fragment>
    <tr><td>First</td></tr>
    <tr><td>Second</td></tr>
  </React.Fragment>
}

2
Чому всі кажуть, що це працює ???? Помилка Uncaught: x.render (): Потрібно повернути дійсний елемент React (або null). Можливо, ви повернули невизначений, масив чи інший недійсний об’єкт.
Xogle

@Xogle Щось, мабуть, змінилося в React API. Здається, це вже не працює.
Петр Пеллер,

1
@FakeRainBrigand Я бачу проблему. Це не "компонент без стану", це функція, що повертає масив. Компоненти без стану не можуть повертати масиви, і ви не можете підключити просту функцію до магазину Redux.
Петр Пеллер,

@PetrPeller ви використовуєте jsx? У прикладі я називаю це як функцію.
Brigand

Я не розумію всіх голосів - це взагалі не відповідає на питання. Питання в тому, як візуалізувати елементи братів і сестер без батьківського елемента, і ця відповідь все одно відображає батьківський елемент.
Dancrumb

33

Я знаю, що це старий допис, але, можливо, моя відповідь може допомогти новачкам, як я.

У React 16.2 була додана покращена підтримка фрагментів .

Тепер ви можете повернути його так:

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

Ви можете обернути його за допомогою <></>або <Fragment></Fragment>.

Якщо ви хочете передати деякі атрибути, під час написання підтримується лише ключ , і вам доведеться використовувати, <Fragment />оскільки короткий синтаксис<></> не приймає атрибути.

Примітка: Якщо ви збираєтеся використовувати короткий синтаксис, переконайтеся, що ви використовуєте Babel 7 .

Посилання на джерело


1
Саме те, за чим я хотів, дякую! Крім того, про всяк випадок, коли це потрібно комусь іншому: імпортуйте React, {Fragment} з 'response'
Кріс,

Здається, я не можу знайти реалізацію Fragmentв їхньому сховищі, може хтось, будь ласка, покаже мені? Дякую :)
Рамон Бальтазар,

Я не можу змусити це працювати, навіть якщо я встановлюю Babel-cli ... навіть лише для рішення <>. Як це можливо @onoya Я незабаром
розміщу

16

Вуху! Команда React нарешті додала цю функцію. Починаючи з React v16.0, ви можете робити:

render() {
  // No need to wrap list items in an extra element!
  return [
    // Don't forget the keys :)
      <tr key="a"><td>Item 1</td></tr>,
      <tr key="b"><td>Item 2</td></tr>
  ];
}

Дивіться повну публікацію в блозі, де пояснюється "Нові типи повернення рендеринга: фрагменти та рядки" тут .


3

Наявність батьківського елемента корисно в більшості випадків, наприклад, у вас може бути батьківський класName, який може орієнтуватись на стиль дочірніх елементів та кілька інших сценаріїв ...

Але, якщо ви дійсно не хочете цього робити, можете скористатися React.Fragment

Тому просто зробіть щось подібне:

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

З версії 16.2 існує також скорочена версія <>, яка також виглядає так у функції рендерингу:

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

Крім того, якщо використовується версія 16.0 і вище, ви можете повернути масив елементів, яким не потрібна батьківська обгортка, як показано нижче:

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

0

Ви можете обернути його в дужки так:

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

Як щодо того, якщо вам також потрібно використовувати Object.keys()в рамках повернення?
Юха Унтінен

Напр. return ( [ <tr><td>Header</td></tr>{ Object.keys(this.props.data).map(function(item) { <tr><td>{data}</td></tr> }) } ] ); З 15.4.2, він дає Unexpected token, expected ,в початковій дужці у відповідь
Juha Untinen

спробуйте щось подібне: return ({Object.keys (this.props.data) .map (function (item) {<tr><td>{data}</td> </tr>}). unshift ({< tr> <td> Заголовок </td> </tr>})});
Віталій Андрусишин

Це не спрацьовує, все одно потрібно мати коми, що розділяють <tr> -s
Філіпп Мунін

0

Цей приклад добре працює для мене:

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

0

Щось на зразок цього синтаксису спрацювало для мене

this.props.map((data,index)=>{return( [ <tr>....</tr>,<tr>....</tr>];)});

-2

Для тих, хто використовує TypeScript, правильний синтаксис:

return [
  (
    <div>Foo</div>
  ),
  (
    <div>Bar</div>
  )
];

1
Це ідентично відповіді @thealexbaron, і це не має нічого спільного з TypeScript
andrewarchi
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.