Помилка розбору: Суміжні елементи JSX повинні бути загорнуті в додаючий тег


467

Я намагаюся налаштувати свою React.jsпрограму так, щоб вона відображалася лише у випадку, якщо я встановила змінну true.

Спосіб налаштування моєї візуалізації виглядає так:

render: function() {
    var text = this.state.submitted ? 'Thank you!  Expect a follow up at '+email+' soon!' : 'Enter your email to request early access:';
    var style = this.state.submitted ? {"backgroundColor": "rgba(26, 188, 156, 0.4)"} : {};
    return (
    <div>

if(this.state.submitted==false) 
{

      <input type="email" className="input_field" onChange={this._updateInputValue} ref="email" value={this.state.email} />

      <ReactCSSTransitionGroup transitionName="example" transitionAppear={true}>
      <div className="button-row">
         <a href="#" className="button" onClick={this.saveAndContinue}>Request Invite</a>
     </div>
     </ReactCSSTransitionGroup>
}
   </div>
    )
  },

По суті, важливою частиною тут є if(this.state.submitted==false)частина (я хочу, щоб ці divелементи відображалися, коли для поданої змінної встановлено false).

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

Неприхована помилка: Помилка розбору: Рядок 38: Суміжні елементи JSX повинні бути загорнуті в додаючий тег

У чому тут питання? І що я можу використати, щоб зробити цю роботу?


3
stackoverflow.com/questions/25034994/… Інші люди тут просто говорять вам використовувати батьківський елемент, але це може бути зайвим. Ця старша версія вашого запитання має цікаву відповідь за допомогою масивів.
Мяу

Відповіді:


636

Ви повинні розмістити свій компонент між додаючим тегом, що означає:

// WRONG!

return (  
    <Comp1 />
    <Comp2 />
)

Замість цього:

// Correct

return (
    <div>
       <Comp1 />
       <Comp2 />
    </div>
)

Редагувати: коментар Джо Клей про API Fragments

// More Correct

return (
    <React.Fragment>
       <Comp1 />
       <Comp2 />
    </React.Fragment>
)

// Short syntax

return (
    <>
       <Comp1 />
       <Comp2 />
    </>
)

4
Що робити, якщо я друкую два ряди разом у таблиці. Як я можу обернути <tr>?
Хосе

235

На це питання вже пізно відповісти, але я подумав, що це додасть пояснення.

Це відбувається тому, що будь-де, де у коді ви повертаєте два елементи одночасно.

напр

return(
    <div id="div1"></div>
    <div id="div1"></div>
  )

Він повинен бути загорнутий у батьківський елемент. напр

 return(
      <div id="parent">
        <div id="div1"></div>
        <div id="div1"></div>
      </div>
      )


Більш детальне пояснення

Ваш нижче jsxкод трансформується

class App extends React.Component {
  render(){
    return (
      <div>
        <h1>Welcome to React</h1>
      </div>
    );
  }
}

в це

_createClass(App, [{
    key: 'render',
    value: function render() {
      return React.createElement(
        'div',
        null,
        React.createElement(
          'h1',
          null,
          'Welcome to React'
        )
      );
    }
  }]);

Але якщо ви це зробите

class App extends React.Component {
  render(){
    return (
        <h1>Welcome to React</h1>
        <div>Hi</div>
    );
  }
}

це перетворюється в це (Просто для ілюстрації, насправді ви отримаєте error : Adjacent JSX elements must be wrapped in an enclosing tag)

_createClass(App, [{
    key: 'render',
    value: function render() {
      return React.createElement(
        'div',
        null,
       'Hi'
      ); 
    return React.createElement(
          'h1',
          null,
          'Welcome to React'
        )
    }
  }]);

У наведеному вище коді ви бачите, що ви намагаєтесь двічі повернутися з виклику методу, що, очевидно, неправильно.

Редагувати - Останні зміни в React 16 та власних палатах:

Якщо ви не хочете додавати додаткових діви, щоб обернутись і хочете повернути більше одного дочірнього компонента, з яким ви можете перейти React.Fragments.

React.Fragments трохи швидше і менше використовує пам'ять (не потрібно створювати додатковий вузол DOM, менше захаращене дерево DOM).

наприклад (у реакт. 16.2.0)

render() {
  return (
    <>
       React fragments.
      <h2>A heading</h2>
      More React fragments.
      <h2>Another heading</h2>
      Even more React fragments.
    </>
  );
}

або

render() {
  return (
    <React.Fragments>
       React fragments.
      <h2>A heading</h2>
      More React fragments.
      <h2>Another heading</h2>
      Even more React fragments.
    <React.Fragments/>
  );
}

або

render() {
 return [
  "Some text.",
  <h2 key="heading-1">A heading</h2>,
  "More text.",
  <h2 key="heading-2">Another heading</h2>,
  "Even more text."
 ];
}

115

Елемент React повинен повертати лише один елемент. Вам доведеться обернути обидва свої теги іншим тегом елемента.

Я також бачу, що ваша функція візуалізації нічого не повертає. Ось як повинен виглядати ваш компонент:

var app = React.createClass({
    render () {
        /*React element can only return one element*/
        return (
             <div></div>
        )
    }
})

Також зауважте, що ви не можете використовувати ifоператори всередині повернутого елемента:

render: function() {
var text = this.state.submitted ? 'Thank you!  Expect a follow up at '+email+' soon!' : 'Enter your email to request early access:';
var style = this.state.submitted ? {"backgroundColor": "rgba(26, 188, 156, 0.4)"} : {};
    if(this.state.submitted==false) {
        return <YourJSX />
    } else {
        return <YourOtherJSX />
    }
},

це не вирішує проблему з "якщо"; Якщо я вилучу "if" у функції візуалізації, він справно працює.
користувач1072337

1
зауважте, що ви не можете користуватися, якщо розмітки всередині переробленого елемента. подивіться на мою оновлену відповідь
Матан Губкін

99

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

// Wrong!
return (  
   <Comp1 />
   <Comp2 />
)

Його можна записати так:

// Correct!
return (  
    [<Comp1 />,
    <Comp2 />]
)

Зауважте, що вищезазначене призведе до попередження: Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of 'YourComponent'.

Це можна виправити, додавши keyатрибут до компонентів, якщо вручну додавати їх, додайте його так:

return (  
    [<Comp1 key="0" />,
    <Comp2 key="1" />]
)

Ось додаткова інформація про клавіші: Склад проти спадкування


7
Я спробував це, і це дає мені помилку. Потрібно повернути дійсний елемент React (або null). Можливо, ви повернули невизначений, масив чи інший недійсний об'єкт.
prasadmsvs

3
@prasadmsvs +1 invariant.js: 39 Неприховане інваріантне порушення: CommitFilter.render (): Дійсний ReactComponent повинен бути повернутий. Можливо, ви повернули невизначений, масив чи інший недійсний об'єкт.
Світлана Іванова

1
Це чудове рішення для випадків, коли вам потрібно / хочете уникати обгорткового елемента!
bloudermilk

2
@aaaaaa це неможливо через спосіб роботи поточного примирення React. Це стек і примирення відбувається рекурсивно. У React 16 це виправлено, і тепер ви можете повернути масив.
natnai

1
github.com/iamdustan/tiny-react-renderer - відмінне сховище, яке повинен прочитати кожен розробник реагування. Як тільки ви це зробите, вам відразу стане зрозуміло, чому нинішня реалізація реакції не дозволяє повернути кількох дітей.
natnai

49

Проблема

Помилка розбору: Суміжні елементи JSX повинні бути загорнуті в додаючий тег

Це означає, що ви намагаєтесь повернути декілька елементів JSX у братських сестер неправильно. Пам’ятайте, що ви пишете не HTML, а JSX! Ваш код перекладається з JSX в JavaScript. Наприклад:

render() {
  return (<p>foo bar</p>);
}

буде перекладено на:

render() {
  return React.createElement("p", null, "foo bar");
}

Якщо ви взагалі не знайомі з програмуванням, ви вже знаєте, що функції / методи (будь-якої мови) приймають будь-яку кількість параметрів, але завжди повертають лише одне значення. Враховуючи це, ви, ймовірно, можете побачити, що проблема виникає при спробі повернути декілька компонентів братів та сестер на основі того, як createElement()працює; він бере лише параметри для одного елемента і повертає це. Отже, ми не можемо повернути кілька елементів з одного виклику функції.


Тож якщо ви коли-небудь замислювалися, чому це працює ...

render() {
  return (
    <div>
      <p>foo</p>
      <p>bar</p>
      <p>baz</p>
    </div>
  );
}

але не це ...

render() {
  return (
    <p>foo</p>
    <p>bar</p>
    <p>baz</p>
  );
}

це тому, що в першому фрагменті обидва <p>-елемента входять до childrenскладу <div>-елемента. Коли вони є частиною, childrenми можемо висловити необмежену кількість елементів братів. Погляньте, як це перетвориться:

render() {
  return React.createElement(
    "div",
    null,
    React.createElement("p", null, "foo"),
    React.createElement("p", null, "bar"),
    React.createElement("p", null, "baz"),
  );
}

Рішення

Залежно від того, яку версію React ви запустите, у вас є кілька варіантів вирішення цього питання:

  • Використовуйте фрагменти (лише React v16.2 +!)

    Станом на React v16.2, React має підтримку фрагментів, що є вузлом без вузлів, який безпосередньо повертає своїх дітей.

    Повернення дітей у масив (див. Нижче) має деякі недоліки:

    • Діти в масиві повинні бути розділені комами.
    • Діти в масиві повинні мати ключ, щоб запобігти попередженню ключа React.
    • Рядки повинні бути загорнуті в лапки.

    Вони усуваються від використання фрагментів. Ось приклад дітей, загорнутих у фрагмент:

    render() {
      return (
        <>
          <ChildA />
          <ChildB />
          <ChildC />
        </>
      );
    }

    який знежирює цукор у:

    render() {
      return (
        <React.Fragment>
          <ChildA />
          <ChildB />
          <ChildC />
        </React.Fragment>
      );
    }

    Зауважте, що для першого фрагмента потрібна версія Babel v7.0 або вище.


  • Повернути масив (лише React v16.0 +!)

    Станом на React v16, React Components може повертати масиви. Це на відміну від попередніх версій React, де вас змусили загортати всі компоненти братів та сестер у батьківський компонент.

    Іншими словами, тепер ви можете:

    render() {
      return [<p key={0}>foo</p>, <p key={1}>bar</p>];
    }

    це перекладається на:

    return [React.createElement("p", {key: 0}, "foo"), React.createElement("p", {key: 1}, "bar")];

    Зверніть увагу, що вище повертає масив. Масиви є дійсними елементами React з React версії 16 та пізнішої версії. Для попередніх версій React масиви не є дійсними об'єктами повернення!

    Також зауважте, що таке недійсне (ви повинні повернути масив):

    render() {
      return (<p>foo</p> <p>bar</p>);
    }

  • Оберніть елементи в батьківський елемент

    Інше рішення передбачає створення материнського компонента, який загортає в нього брати-компоненти children. Це, безумовно, найпоширеніший спосіб вирішення цього питання і працює у всіх версіях React.

    render() {
      return (
        <div>
          <h1>foo</h1>
          <h2>bar</h2>
        </div>
      );
    }

    Примітка. Погляньте ще раз у верхню частину цієї відповіді, щоб отримати докладнішу інформацію та як це транслюється .


@Grievoushead, не для компонентів, ні. Тільки для дітей.
Кріс

1
Приємний, виправлений питання для мене.
Сохан

1
Дякую Крису за те, що знайшов час для пояснення інших рішень!
Marvel Moe

на React v16.4перший приклад не працює, використовуючи:, <>only <React.Fragment>:(
vsync

@vsync підтримка цього синтаксису залежить від вашого будівельного середовища. Не впевнений, чи підтримує це ще ніколи, і якщо так, то яка версія.
Кріс

22

Реагуючи 16.0.0, ми можемо повернути декілька компонентів з візуалізації як масив.

return ([
    <Comp1 />,
    <Comp2 />
]);

Реагуючи 16.4.0, ми можемо повернути декілька компонентів від візуалізації в тезі Fragment. Фрагмент

return (
<React.Fragment>
    <Comp1 />
    <Comp2 />
</React.Fragment>);

Future React, ви зможете використовувати цей скорочений синтаксис. (багато інструментів ще не підтримують його, тому ви можете явно написати, <Fragment>поки інструмент не наздожене.)

return (
<>
    <Comp1 />
    <Comp2 />
</>)

1
Ви забули ,між компонентами. Це масив, тому вам потрібно відокремити кожен елемент всередині нього.
Кріс

Ні <Fragment>, це <React.Fragment>. говорить про це у власному посиланні
vsync

2
Якщо ви руйнуєте, import React { Fragment } from 'react';то ви використовуєте це так<Fragment >
Morris S

7

Якщо ви не завертаєте свій компонент, ви можете написати його, як зазначено нижче.

Замість:

return(
  <Comp1 />
  <Comp2 />
     );

Ви можете написати це:

return[(
 <Comp1 />
),
(
<Comp2 />
) ];

6

це дуже просто, ми можемо використовувати батьківський елемент div, щоб обернути весь елемент, або ми можемо використовувати концепцію компонента вищого порядку (HOC's), тобто дуже корисно для реагування на додатки js

render() {
  return (
    <div>
      <div>foo</div>
      <div>bar</div>
    </div>
  );
}

або інший кращий спосіб - HOC його дуже простий не дуже складний, просто додайте файл hoc.js у свій проект і просто додайте ці коди

const aux = (props) => props.children;
export default aux;

тепер імпортуйте файл hoc.js, куди ви хочете використовувати, тепер замість обгортання з елементом div ми можемо обернутись hoc.

import React, { Component } from 'react';
import Hoc from '../../../hoc';

    render() {
      return (
    <Hoc>
        <div>foo</div>
        <div>bar</div>
    </Hoc>
      );
    }

Хоча цей код може відповісти на питання, надаючи додатковий контекст щодо того, як та / або чому він вирішує проблему, покращить довгострокове значення відповіді. Прочитайте це .
Shanteshwar Inde

Це не HoC, це простий компонент, який дублює функціональність Fragmentкомпонента.
Еміль Бержерон

4

Є в реакції правило, що вираз JSX повинен містити рівно один зовнішній елемент.

неправильно

const para = (
    <p></p>
    <p></p>
);

правильно

const para = (
    <div>
        <p></p>
        <p></p>
    </div>
);

1

React 16 отримує ваше повернення як масив, тому його слід обернути одним елементом, як div.

Неправильний підхід

render(){
    return(
    <input type="text" value="" onChange={this.handleChange} />

     <button className="btn btn-primary" onClick=   {()=>this.addTodo(this.state.value)}>Submit</button>

    );
}

Правильний підхід (усі елементи в одному або іншому елементі, який ви використовуєте)

render(){
    return(
        <div>
            <input type="text" value="" onChange={this.handleChange} />

            <button className="btn btn-primary" onClick={()=>this.addTodo(this.state.value)}>Submit</button>
        </div>
    );
}

1

Компоненти реагування повинні бути загорнуті в один контейнер, це може бути будь-який тег, наприклад "<div> .. </div>"

Ви можете перевірити метод візуалізації ReactCSSTransitionGroup


0

Імпорт подання та завершення View. Обгортання у divмене не вийшло.

import { View } from 'react-native';
...
    render() {
      return (
        <View>
          <h1>foo</h1>
          <h2>bar</h2>
        </View>
      );
    }

2
це тому, що ви використовуєте рідну реакцію.
Нік H247

А фрагменти також доступні в React Native, тому це Viewнасправді не найкраще рішення.
Еміль Бержерон

0

Недійсне: не лише дочірні елементи

render(){
        return(
            <h2>Responsive Form</h2>
            <div>Adjacent JSX elements must be wrapped in an enclosing tag</div>
            <div className="col-sm-4 offset-sm-4">
                <form id="contact-form" onSubmit={this.handleSubmit.bind(this)} method="POST">
                    <div className="form-group">
                        <label for="name">Name</label>
                        <input type="text" className="form-control" id="name" />
                    </div>
                    <div className="form-group">
                        <label for="exampleInputEmail1">Email address</label>
                        <input type="email" className="form-control" id="email" aria-describedby="emailHelp" />
                    </div>
                    <div className="form-group">
                        <label for="message">Message</label>
                        <textarea className="form-control" rows="5" id="message"></textarea>
                    </div>
                    <button type="submit" className="btn btn-primary">Submit</button>
                </form>
            </div>
        )
    }

Дійсно: Корінний елемент під дочірніми елементами

render(){
        return(
          <div>
            <h2>Responsive Form</h2>
            <div>Adjacent JSX elements must be wrapped in an enclosing tag</div>
            <div className="col-sm-4 offset-sm-4">
                <form id="contact-form" onSubmit={this.handleSubmit.bind(this)} method="POST">
                    <div className="form-group">
                        <label for="name">Name</label>
                        <input type="text" className="form-control" id="name" />
                    </div>
                    <div className="form-group">
                        <label for="exampleInputEmail1">Email address</label>
                        <input type="email" className="form-control" id="email" aria-describedby="emailHelp" />
                    </div>
                    <div className="form-group">
                        <label for="message">Message</label>
                        <textarea className="form-control" rows="5" id="message"></textarea>
                    </div>
                    <button type="submit" className="btn btn-primary">Submit</button>
                </form>
            </div>
          </div>
        )
    }

Будь ласка, уникайте відповідей типу "я теж" чи повторення того ж рішення, якщо у вас є щось відповідне, щоб додати його.
Еміль Бержерон

-1

Для розробників Rect-Native. Я зіткнувся з цією помилкою під час рендерінгаItem у FlatList. У мене було два компоненти тексту. Я використовував їх, як нижче

renderItem = { ({item}) => 
     <Text style = {styles.item}>{item.key}</Text>
     <Text style = {styles.item}>{item.user}</Text>
}

Але після того, як я поклав ці буксирні компоненти Inside View, це працювало на мене.

renderItem = { ({item}) => 
   <View style={styles.flatview}>
      <Text style = {styles.item}>{item.key}</Text>
      <Text style = {styles.item}>{item.user}</Text>
   </View>
 }

Можливо, ви використовуєте інші компоненти, але розміщення їх у View може працювати для вас.


Фрагменти також доступні в React Native, тому це Viewнасправді не найкраще рішення.
Еміль Бержерон

-1

Я думаю, що ускладнення може виникнути і при спробі вкласти кілька Divs у зворотній заяві. Ви можете зробити це, щоб ваші компоненти відображалися як елементи блоку.

Ось приклад правильної візуалізації пари компонентів, використовуючи кілька дівок.

return (
  <div>
    <h1>Data Information</H1>
    <div>
      <Button type="primary">Create Data</Button>
    </div>
  </div>
)

-1

У мене виникла проблема, яка спричинила цю помилку, яка не була очевидною.

const App = () => {
  return (
      <div className="App">
        <h1>Hello CodeSandbox</h1>
        <h2>Start editing to see some magic happen!</h2>
      </div>
  )
}

І ось виправлення ...

const App = () => {
  return (
      <div className="AppClassName">       <--- note the change
        <h1>Hello CodeSandbox</h1>
        <h2>Start editing to see some magic happen!</h2>
      </div>
  )
}

Піди розберися. Тут ділиться інформацією на випадок, якщо інші вдарять про це. Мабуть, у вас не може бути ім'я класу елемента таким же, як його ім'я батьківської функції React.


Це не правда. Це навіть за замовчуванням у шаблоні codeandbox React. Щось ще повинно було суперечити цьому імені класу.
Еміль Бержерон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.