Я пытаюсь настроить приложение 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 должны быть заключены в тег
В чем здесь проблема? И что я могу использовать, чтобы сделать эту работу?
Вы должны поместить свой компонент между тегом, который означает:
// WRONG!
return (
<Comp1 />
<Comp2 />
)
Вместо:
// Correct
return (
<div>
<Comp1 />
<Comp2 />
</div>
)
Редактировать: Per Joe Clay комментарий об API фрагментов
// More Correct
return (
<React.Fragment>
<Comp1 />
<Comp2 />
</React.Fragment>
)
Уже поздно отвечать на этот вопрос, но я подумал, что это добавит объяснения.
Это происходит потому, что в любом месте вашего кода вы возвращаете два элемента одновременно.
например
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 должен возвращать только один элемент. Вам придется обернуть оба тега другим тегом элемента.
Я также вижу, что ваша функция рендеринга ничего не возвращает. Вот как должен выглядеть ваш компонент:
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 />
}
},
Если вы не хотите обертывать его в другой 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
Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of 'ContentContainer'.
Ошибка анализа: смежные элементы 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 поддерживает Фрагменты, который является компонентом node без возврата, который возвращает своих детей напрямую.
Возврат дочерних элементов в массиве (см. ниже) имеет некоторые недостатки:
- Дети в массиве должны быть разделены запятыми.
- У детей в массиве должен быть ключ, предупреждающий клавишу Reacts.
- Строки должны быть заключены в кавычки.
Они исключаются из использования фрагментов. Вот пример детей, завернутых в фрагмент:
render() {
return (
<>
<ChildA />
<ChildB />
<ChildC />
</>
);
}
который de-sugars в:
render() {
return (
<React.Fragment>
<ChildA />
<ChildB />
<ChildC />
</React.Fragment>
);
}
Обратите внимание, что для первого фрагмента требуется Babel v7.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>
);
}
Примечание. Посмотрите еще раз в верхней части этого ответа для получения более подробной информации и того, как это происходит.
Реагируя на 16.0.0, мы можем вернуть несколько компонентов рендеринга в виде массива.
return ([
<Comp1 />,
<Comp2 />
]);
Реагируя на 16.4.0, мы можем вернуть несколько компонентов рендера в теге Fragment. Фрагмент
return (
<React.Fragment>
<Comp1 />
<Comp2 />
</React.Fragment>);
Реакция на будущее вы сможете использовать этот сокращенный синтаксис. (многие инструменты еще не поддерживают его, поэтому вы можете явно написать <Fragment>
пока инструмент не догонит.)
return (
<>
<Comp1 />
<Comp2 />
</>)
,
между компонентами. Это массив, поэтому вам нужно отделить каждый элемент внутри него.
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>
);
}
Неверно: не только дочерние элементы
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>
)
}
Импортировать представление и завернуть в View
. Обертка в div
не работала для меня.
import { View } from 'react-native';
...
render() {
return (
<View>
<h1>foo</h1>
<h2>bar</h2>
</View>
);
}
Реактивные компоненты должны быть упакованы в один контейнер, который может быть любым тегом, например "<div>.. </div>"
Вы можете проверить метод визуализации ReactCSSTransitionGroup