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

IT技术 javascript reactjs render
2021-01-15 23:27:17

我正在尝试设置我的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 元素包装在封闭标记中

这里有什么问题?我可以用什么来完成这项工作?

6个回答

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

// 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 />
    </>
)
@Jose 您可以使用 Fragments API,如答案所示,它们不会产生任何额外的 DOM 元素。
2021-03-15 23:27:17
如果我在表格中一起打印 2 行怎么办。我怎样才能包装 <tr>?
2021-03-27 23:27:17

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

这是因为您在代码中的任何地方同时返回两个元素。

例如

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 和自己的病房的最新变化:

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

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."
 ];
}

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 语句。看看我更新的答案
2021-03-14 23:27:17
这并没有解决“如果”的问题;如果我删除渲染函数中的“if”,它工作正常。
2021-03-27 23:27:17

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

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

@prasadmsvs +1 invariant.js:39 Uncaught Invariant Violation: CommitFilter.render(): 必须返回一个有效的 ReactComponent。您可能返回了 undefined、数组或其他一些无效对象。
2021-03-15 23:27:17
我试过这个,它给了我一个错误。必须返回有效的 React 元素(或 null)。您可能返回了 undefined、数组或其他一些无效对象。
2021-03-17 23:27:17
对于您需要/想要避免使用包装元素的时候,这是一个很好的解决方案!
2021-03-22 23:27:17
@aaaaaa 这是不可能的,因为当前 React 协调器的工作方式。它是一个堆栈,并且以递归方式进行协调。在 React 16 中这是固定的,您现在可以返回一个数组。
2021-03-25 23:27:17
github.com/iamdustan/tiny-react-renderer是一个优秀的存储库,每个React开发人员都应该阅读。一旦你这样做了,你应该立即明白为什么 react 的当前实现不允许返回多个孩子。
2021-03-31 23:27:17

问题

解析错误:必须将相邻的 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 版本,您有几个选项可以解决这个问题:

  • 使用片段(仅限 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 或更高版本。


  • 返回一个数组(仅限 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 元素。对于早期版本的 React,数组不是有效的返回对象!

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

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

  • 将元素包裹在父元素中

    另一种解决方案涉及创建一个父组件,该组件将兄弟组件包装在其children. 这是迄今为止解决此问题的最常见方法,并且适用于所有版本的 React。

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

    注意:再次查看此答案的顶部以了解更多详细信息以及它如何转换.

在 React 上v16.4,第一个示例不能使用: <>,只有<React.Fragment>:(
2021-03-13 23:27:17
@Grievoushead,不适用于组件,不是。只为儿童。
2021-03-19 23:27:17
@vsync 对该语法的支持因您的构建环境而异。不确定 babel 是否支持它,如果支持,是哪个版本。
2021-04-01 23:27:17
@Chris - 谢谢。我在Codepen尝试过,切换了本地Babel复选框
2021-04-09 23:27:17