Ошибка разбора: смежные элементы JSX должны быть заключены в тег

286

Я пытаюсь настроить приложение 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).

Но при запуске этого я получаю ошибку в вопросе:

Uncaught Error: Parse Error: Строка 38: Соседние элементы JSX должны быть заключены в тег

В чем здесь проблема? И что я могу использовать, чтобы сделать эту работу?

  • 3
    stackoverflow.com/questions/25034994/… Другие люди здесь просто говорят вам использовать родительский элемент, но это может быть ненужным. Эта старая версия вашего вопроса имеет интересный ответ с использованием массивов.
  • 1
    на этом этапе вы должны принять одобренный ответ.
Показать ещё 1 комментарий
Теги:
render

10 ответов

435

Вы должны поместить свой компонент между тегом, который означает:

// WRONG!

return (  
    <Comp1 />
    <Comp2 />
)

Вместо:

// Correct

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

Редактировать: Per Joe Clay комментарий об API фрагментов

// More Correct

return (
    <React.Fragment>
       <Comp1 />
       <Comp2 />
    </React.Fragment>
)
  • 41
    Поскольку этот вопрос / ответ в настоящее время является лучшим результатом Google для этого сообщения об ошибке, я хотел бы отметить, что с тех пор React добавил API фрагментов , который позволяет вам достичь того же самого, не добавляя дополнительные узлы DOM.
  • 2
    Что делать, если я печатаю 2 строки вместе в таблице. Как я могу обернуть <tr>?
150

Уже поздно отвечать на этот вопрос, но я подумал, что это добавит объяснения.

Это происходит потому, что в любом месте вашего кода вы возвращаете два элемента одновременно.

например

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

В приведенном выше коде вы можете видеть, что вы пытаетесь дважды вернуться из вызова метода, что, очевидно, неправильно.

  • 1
    Это очень хорошее объяснение. Спасибо @witVault
92

Элемент 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 />
    }
},
  • 0
    это не решает проблему с «если»; Если я удаляю «если» из функции рендеринга, она работает нормально.
  • 0
    Также, если вы посмотрите выше, у меня есть функция возврата в вопросе ...
Показать ещё 1 комментарий
76

Если вы не хотите обертывать его в другой div, как предложили другие ответы, вы можете также обернуть его в массив, и он будет работать.

// 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" />]
)

Вот еще информация о клавишах: http://facebook.github.io/react/docs/multiple-components.html#dynamic-children

  • 0
    «Правильный» способ здесь предупреждает: Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of 'ContentContainer'.
  • 0
    Вы можете просто добавить ключ к компонентам, чтобы избежать этого предупреждения. Проверьте здесь facebook.github.io/react/docs/…
Показать ещё 16 комментариев
48

Проблема

Ошибка анализа: смежные элементы JSX должны быть заключены в тег

Это означает, что вы пытаетесь вернуть несколько элементов JSX дочернего узла неверным образом. Помните, что вы не пишете HTML, а JSX! Ваш код транслируется из JSX в JavaScript. Например:

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

будет транслироваться в:

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

Если вы вообще не новичок в программировании, вы уже знаете, что функции/методы (любого языка) принимают любое количество параметров, но всегда возвращают только одно значение. Учитывая это, вы, вероятно, увидите, что возникает проблема при попытке вернуть несколько компонентов sibling на основе того, как работает 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 поддерживает Фрагменты, который является компонентом node без возврата, который возвращает своих детей напрямую.

    Возврат дочерних элементов в массиве (см. ниже) имеет некоторые недостатки:

    • Дети в массиве должны быть разделены запятыми.
    • У детей в массиве должен быть ключ, предупреждающий клавишу Reacts.
    • Строки должны быть заключены в кавычки.

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

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

    который de-sugars в:

    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 с версии 16 и более поздних версий. Для более ранних версий React массивы недействительны возвращаемым объектам!

    Также обратите внимание, что следующее недействительно (вы должны вернуть массив):

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

  • Оберните элементы в родительский элемент

    Другое решение включает создание родительского компонента, который обертывает дочерние компоненты в children. Это, безусловно, самый распространенный способ решения этой проблемы и работает во всех версиях React.

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

    Примечание. Посмотрите еще раз в верхней части этого ответа для получения более подробной информации и того, как это происходит.

  • 0
    Возврат массива также работает в 15 версии
  • 0
    @ Гривухед, не для компонентов, нет. Только для детей.
Показать ещё 5 комментариев
19

Реагируя на 16.0.0, мы можем вернуть несколько компонентов рендеринга в виде массива.

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

Реагируя на 16.4.0, мы можем вернуть несколько компонентов рендера в теге Fragment. Фрагмент

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

Реакция на будущее вы сможете использовать этот сокращенный синтаксис. (многие инструменты еще не поддерживают его, поэтому вы можете явно написать <Fragment> пока инструмент не догонит.)

return (
<>
    <Comp1 />
    <Comp2 />
</>)
  • 1
    Вы забыли , между компонентами. Это массив, поэтому вам нужно отделить каждый элемент внутри него.
  • 0
    Это верно, спасибо за указание, исправлено!
Показать ещё 3 комментария
2

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>

    );
}

Правильный подход (все элементы в одном div или другом элементе, который вы используете)

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

Неверно: не только дочерние элементы

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

Импортировать представление и завернуть в View. Обертка в div не работала для меня.

import { View } from 'react-native';
...
    render() {
      return (
        <View>
          <h1>foo</h1>
          <h2>bar</h2>
        </View>
      );
    }
  • 1
    это потому, что вы используете реагировать родной.
0

Реактивные компоненты должны быть упакованы в один контейнер, который может быть любым тегом, например "<div>.. </div>"

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню