解析错误:相邻的JSX元素必须包装在一个封闭标签中


466

我正在尝试设置我的 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/… 这里的其他人只是告诉您使用父元素,但这可能是不必要的。您的问题的较旧版本使用数组有一个有趣的答案。
2016年

Answers:


636

您应该将组件放在一个封闭标签之间,这意味着:

// WRONG!

return (  
    <Comp1 />
    <Comp2 />
)

代替:

// Correct

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

编辑: Per Joe Clay关于Fragments API的评论

// More Correct

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

// Short syntax

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

4
如果我在表中一起打印2行怎么办?如何包装<tr>?
何塞(Jose)

233

回答这个问题为时已晚,但我认为这将增加解释。

之所以发生这种情况,是因为您在代码中的任何位置同时返回两个元素。

例如

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

这被转换成this(仅出于说明目的,实际上您会得到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和自己的区域中的最新更改:

如果您不想添加额外的div来回绕并且想返回多个子组件,则可以使用React.Fragments

React.Fragments 速度更快一点,内存使用量更少(无需创建额外的DOM节点,减少了混乱的DOM树)。

例如(在React 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”解决问题;如果我在渲染函数中删除了“ if”,则可以正常工作。
user1072337

1
请注意,如果语句位于重新调整的元素内,则不能使用。看看我最新的答案
Matan Gubkin

99

如果您不想像其他答案所建议的那样将其包装在另一个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" />]
)

以下是有关键的更多信息:组合与继承


7
我试过了,这给了我一个错误。必须返回有效的React元素(或null)。您可能返回了undefined,数组或其他无效对象。
prasadmsvs's

3
@prasadmsvs +1 invariant.js:39未捕获的不变违规:CommitFilter.render():必须返回有效的ReactComponent。您可能返回了undefined,数组或其他无效对象。
Svetlana Ivanova

1
对于需要/想要避免包装元素的时代,这是一个很好的解决方案!
bloudermilk

2
@aaaaaa不可能,因为当前的React协调器的工作方式。它是一个堆栈,对帐以递归方式进行。在React 16中,此问题已修复,您现在可以返回一个数组。
natnai

1
github.com/iamdustan/tiny-react-renderer是一个优秀的存储库,每个React开发人员都应阅读。完成后,您应该立即明白为什么当前的react实现不允许返回多个子代。
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>-elements是部分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版本,您确实可以通过几种方法来解决此问题:

  • 使用片段(仅适用于v16.2 +!)

    从React v16.2开始,React支持Fragments,是一个无节点组件,可直接返回其子级。

    返回数组中的子级(见下文)有一些缺点:

    • 数组中的子项必须用逗号分隔。
    • 数组中的子代必须具有密钥,以防止React发出密钥警告。
    • 字符串必须用引号引起来。

    这些都从使用片段中消除。这是包裹在片段中的孩子的示例:

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

    哪个糖变成:

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

    请注意,第一个片段需要Babel v7.0或更高版本。


  • 返回一个数组(仅适用于v16.0 +!)

    从React v16开始,React组件可以返回数组。这与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 Elements。对于较早版本的React,数组不是有效的返回对象!

    另请注意,以下内容无效(您必须返回一个数组):

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

  • 将元素包装在父元素中

    另一种解决方案涉及创建一个父组件,该组件将同级组件包装在中children。到目前为止,这是解决此问题的最常用方法,并且适用于所有版本的React。

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

    注意:再次查看此答案的顶部,以获取更多详细信息以及如何转换


@Grievoushead,不用于组件,不。仅适用于儿童。
克里斯(Chris)

1
不错,我已解决了一个问题。
索韩

1
感谢克里斯花时间解释其他解决方案!
Marvel Moe

在React上v16.4,第一个示例无法使用:<>,仅使用<React.Fragment>:(
vsync

@vsync对语法的支持因您的建筑环境而异。不确定babel是否支持它,如果支持,则支持哪个版本。
克里斯(Chris)

22

React 16.0.0我们可以将render中的多个组件作为一个数组返回。

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

在React 16.4.0中,我们可以从Fragment标签中的render返回多个组件。分段

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

Future React您将能够使用此速记语法。(许多工具尚不支持它,因此您可能要显式编写<Fragment>直到工具赶上来。)

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

1
,在组件之间忘记了。它是一个数组,因此您需要分离其中的每个元素。
克里斯(Chris)

没有<Fragment>,是<React.Fragment>。在您自己的链接中这样说
vsync

2
如果您要进行销毁,import React { Fragment } from 'react';则可以这样使用<Fragment >
Morris S

7

如果不包装组件,则可以按以下方法编写。

代替:

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

你可以这样写:

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

6

非常简单,我们可以使用父元素div来包装所有元素,也可以使用高阶组件(HOC's)概念,即对react 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组件的功能。
Emile Bergeron

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>

    );
}

正确的方法(您正在使用的一个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

React组件必须包装在单个容器中,该容器可以是任何标签, 例如“ <div> .. </ div>”

您可以检查ReactCSSTransitionGroup的渲染方法


0

导入视图并包装View。包装一个div对我没有用。

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

2
那就是因为您使用的是本机反应。
尼克H247,18年

而且片段也可以在React Native中使用,因此a View并不是真正的最佳解决方案。
Emile Bergeron

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

请避免使用“我也是”类型的答案或重复相同的解决方案,除非您需要添加一些相关内容。
Emile Bergeron

-1

对于Rect-Native开发人员。FlatList中的renderItem时遇到此错误。我有两个文本组件。我像下面一样使用它们

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

但是,在将这些拖曳放入“内部视图组件”后,它对我有用。

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

您可能正在使用其他组件,但是将它们放入View可能对您有用。


片段也可以在React Native中使用,因此a View并不是真正的最佳解决方案。
Emile Bergeron

-1

我认为当尝试在return语句中嵌套多个Div时,也可能会出现这种复杂情况。您可能希望这样做,以确保您的组件呈现为块元素。

这是一个使用多个div正确渲染几个组件的示例。

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模板中的默认值。某些其他东西必须与此类名冲突。
Emile Bergeron
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.