Lỗi phân tích cú pháp: Các phần tử JSX liền kề phải được bọc trong một thẻ kèm theo


467

Tôi đang cố gắng thiết lập React.jsứng dụng của mình để nó chỉ hiển thị nếu một biến tôi đã đặt là true.

Cách thức chức năng kết xuất của tôi được thiết lập trông như sau:

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

Về cơ bản, phần quan trọng ở đây là if(this.state.submitted==false)phần (tôi muốn các divphần tử này hiển thị khi biến được gửi được đặt thành false).

Nhưng khi chạy cái này, tôi gặp lỗi trong câu hỏi:

Uncaught Error: Parse Error: Line 38: Các phần tử JSX liền kề phải được bọc trong một thẻ kèm theo

Vấn đề ở đây là gì? Và tôi có thể sử dụng những gì để làm cho công việc này?


3
stackoverflow.com/questions/25034994/ Mạnh Những người khác ở đây chỉ bảo bạn sử dụng phần tử cha, nhưng điều đó có thể không cần thiết. Phiên bản cũ hơn của câu hỏi của bạn có một câu trả lời thú vị bằng cách sử dụng mảng.
Meow

Câu trả lời:


636

Bạn nên đặt thành phần của mình giữa một thẻ kèm theo, có nghĩa là:

// WRONG!

return (  
    <Comp1 />
    <Comp2 />
)

Thay thế:

// Correct

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

Chỉnh sửa: Nhận xét của Per Joe Clay về API Fragment

// More Correct

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

// Short syntax

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

4
Điều gì xảy ra nếu tôi in 2 hàng với nhau trong một bảng. Làm cách nào tôi có thể quấn <tr>?
Jose

235

Vẫn còn muộn để trả lời câu hỏi này nhưng tôi nghĩ nó sẽ thêm vào lời giải thích.

Nó đang xảy ra bởi vì bất kỳ nơi nào trong mã của bạn, bạn sẽ trả lại hai phần tử cùng một lúc.

ví dụ

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

Nó nên được bọc trong một yếu tố cha mẹ . ví dụ

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


Giải thích chi tiết hơn

jsxMã dưới đây của bạn được chuyển đổi

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

vào đây

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

Nhưng nếu bạn làm điều này

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

cái này được chuyển thành cái này (Chỉ với mục đích minh họa, thực sự bạn sẽ nhận được 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'
        )
    }
  }]);

Trong đoạn mã trên, bạn có thể thấy rằng bạn đang cố gắng trả về hai lần từ một cuộc gọi phương thức, điều này rõ ràng là sai.

Chỉnh sửa- Những thay đổi mới nhất trong Phản ứng 16 và phường riêng:

Nếu bạn không muốn thêm div để bọc và muốn trả lại nhiều hơn một thành phần con bạn có thể đi cùng React.Fragments.

React.Fragments nhanh hơn một chút và sử dụng ít bộ nhớ hơn (không cần tạo thêm nút DOM, cây DOM ít lộn xộn hơn).

ví dụ: (Trong phản ứng 16.2.0)

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

hoặc là

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

hoặc là

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

115

Phần tử phản ứng chỉ phải trả về một phần tử. Bạn sẽ phải bọc cả hai thẻ của mình bằng một thẻ phần tử khác.

Tôi cũng có thể thấy rằng chức năng kết xuất của bạn không trả lại bất cứ điều gì. Đây là cách thành phần của bạn sẽ trông như thế nào:

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

Cũng lưu ý rằng bạn không thể sử dụng các ifcâu lệnh bên trong phần tử được trả về:

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 />
    }
},

điều này không giải quyết vấn đề với "nếu"; Nếu tôi loại bỏ "nếu" trong chức năng kết xuất, nó sẽ hoạt động tốt.
dùng1072337

1
lưu ý rằng bạn không thể sử dụng nếu các số liệu bên trong phần tử được trả về. nhìn vào câu trả lời cập nhật của tôi
Matan Gubkin

99

Nếu bạn không muốn gói nó trong một div khác như các câu trả lời khác đã đề xuất, bạn cũng có thể gói nó trong một mảng và nó sẽ hoạt động.

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

Nó có thể được viết là:

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

Xin lưu ý rằng những điều trên sẽ tạo ra một cảnh báo: Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of 'YourComponent'.

Điều này có thể được khắc phục bằng cách thêm một keythuộc tính cho các thành phần, nếu thêm thủ công thêm nó như sau:

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

Dưới đây là một số thông tin về các phím: Thành phần so với Kế thừa


7
Tôi đã thử điều này và nó cho tôi một lỗi. Một phần tử React hợp lệ (hoặc null) phải được trả về. Bạn có thể đã trả lại không xác định, một mảng hoặc một số đối tượng không hợp lệ khác.
prasadmsvs

3
@prasadmsvs +1 invariant.js: 39 Vi phạm bất biến Uncaught: CommitFilter.render (): Phải trả lại ReactComponent hợp lệ. Bạn có thể đã trả lại không xác định, một mảng hoặc một số đối tượng không hợp lệ khác.
Svetlana Ivanova

1
Đây là một giải pháp tuyệt vời cho những lúc bạn cần / muốn tránh một yếu tố bao bọc!
bloudermilk

2
@aaaaaa không thể vì cách hoạt động của trình điều hòa React hiện tại. Nó là một chồng và hòa giải được thực hiện đệ quy. Trong React 16, điều này là cố định và bây giờ bạn có thể trả về một mảng.
natnai

1
github.com/iamdustan/tiny-react-renderer là một kho lưu trữ tuyệt vời mà mọi nhà phát triển phản ứng nên đọc. Khi bạn làm như vậy, nó sẽ trở nên rõ ràng ngay lập tức với bạn tại sao việc thực hiện phản ứng hiện tại không cho phép trả lại nhiều trẻ em.
natnai

49

Vấn đề

Lỗi phân tích cú pháp: Các phần tử JSX liền kề phải được bọc trong một thẻ kèm theo

Điều này có nghĩa là bạn đang cố gắng trả lại nhiều phần tử JSX theo cách không chính xác. Hãy nhớ rằng bạn không viết HTML, mà là JSX! Mã của bạn được dịch mã từ JSX sang JavaScript. Ví dụ:

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

sẽ được dịch vào:

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

Trừ khi bạn chưa quen với lập trình nói chung, bạn đã biết rằng các hàm / phương thức (của bất kỳ ngôn ngữ nào) có bất kỳ số lượng tham số nào nhưng luôn chỉ trả về một giá trị. Cho rằng, bạn có thể thấy rằng một vấn đề phát sinh khi cố gắng trả lại nhiều thành phần anh chị em dựa trên cách createElement()hoạt động; nó chỉ lấy tham số cho một phần tử và trả về nó. Do đó chúng ta không thể trả về nhiều phần tử từ một lệnh gọi hàm.


Vì vậy, nếu bạn đã từng tự hỏi tại sao điều này hoạt động ...

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

nhưng không phải ...

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

đó là vì trong đoạn đầu tiên, cả hai <p>-elements là một phần của childrencác <div>-element. Khi chúng là một phần của childrenchúng ta có thể thể hiện vô số yếu tố anh chị em. Hãy xem làm thế nào điều này sẽ transpile:

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

Các giải pháp

Tùy thuộc vào phiên bản React nào bạn đang chạy, bạn có một vài tùy chọn để giải quyết vấn đề này:

  • Sử dụng các đoạn (Chỉ phản ứng v16.2 +!)

    Kể từ React v16.2, React có hỗ trợ cho Fragment , một thành phần không có nút trả về con trực tiếp.

    Trả lại những đứa trẻ trong một mảng (xem bên dưới) có một số nhược điểm:

    • Trẻ em trong một mảng phải được phân tách bằng dấu phẩy.
    • Trẻ em trong một mảng phải có chìa khóa để ngăn cảnh báo khóa của React.
    • Chuỗi phải được bọc trong dấu ngoặc kép.

    Chúng được loại bỏ khỏi việc sử dụng các mảnh vỡ. Đây là một ví dụ về trẻ em được bọc trong một mảnh:

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

    mà de-đường vào:

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

    Lưu ý rằng đoạn mã đầu tiên yêu cầu Babel v7.0 trở lên.


  • Trả về một mảng (Chỉ phản ứng v16.0 +!)

    Kể từ React v16, các thành phần React có thể trả về mảng. Điều này không giống như các phiên bản trước của React khi bạn buộc phải bọc tất cả các thành phần anh chị em trong thành phần cha mẹ.

    Nói cách khác, bây giờ bạn có thể làm:

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

    transpiles này vào:

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

    Lưu ý rằng ở trên trả về một mảng. Mảng là các yếu tố React hợp lệ kể từ React phiên bản 16 trở lên. Đối với các phiên bản trước của React, mảng không phải là đối tượng trả về hợp lệ!

    Cũng lưu ý rằng những điều sau đây không hợp lệ (bạn phải trả về một mảng):

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

  • Bao bọc các phần tử trong phần tử cha

    Giải pháp khác liên quan đến việc tạo ra một thành phần cha mẹ bao bọc các thành phần anh chị em trong nó children. Đây là cách phổ biến nhất để giải quyết vấn đề này và hoạt động trong tất cả các phiên bản của React.

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

    Lưu ý: Hãy xem lại ở đầu câu trả lời này để biết thêm chi tiết và cách thức dịch mã này .


@Grievoushead, không cho các thành phần, không. Chỉ dành cho trẻ em.
Chris

1
Đẹp một, vấn đề cố định với tôi.
Sohan

1
Cảm ơn Chris đã dành thời gian để giải thích các giải pháp khác!
Marvel Moe

trên React v16.4ví dụ đầu tiên không hoạt động bằng cách sử dụng : <>, chỉ <React.Fragment>:(
vsync

@vsync sự hỗ trợ cho cú pháp đó khác nhau tùy theo môi trường xây dựng của bạn. Không chắc chắn nếu babel hỗ trợ nó chưa, và nếu vậy, phiên bản nào.
Chris

22

Phản ứng 16.0.0 chúng ta có thể trả về nhiều thành phần từ kết xuất dưới dạng một mảng.

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

Phản ứng 16.4.0 chúng ta có thể trả về nhiều thành phần từ kết xuất trong thẻ Fragment. Miếng

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

Tương lai React bạn sẽ có thể sử dụng cú pháp tốc ký này. (nhiều công cụ chưa hỗ trợ nó nên bạn có thể muốn viết rõ ràng <Fragment>cho đến khi công cụ bắt kịp.)

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

1
Bạn đã quên một ,giữa các thành phần. Đó là một mảng vì vậy bạn cần tách từng phần tử bên trong nó.
Chris

Không <Fragment>, đó là <React.Fragment>. nói như vậy trong liên kết của riêng bạn
vsync

2
Nếu bạn đang phá hoại import React { Fragment } from 'react';thì bạn hãy sử dụng nó như thế này<Fragment >
Morris S

7

Nếu bạn không bọc thành phần của mình thì bạn có thể viết nó như phương pháp được đề cập dưới đây.

Thay vì:

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

bạn có thể viết điều này:

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

6

Rất đơn giản, chúng ta có thể sử dụng div phần tử cha để bao bọc tất cả phần tử hoặc chúng ta có thể sử dụng khái niệm Thành phần bậc cao (HOC) tức là rất hữu ích để phản ứng các ứng dụng js

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

hoặc một cách tốt nhất khác là HOC rất đơn giản, không phức tạp lắm, chỉ cần thêm một tệp hoc.js trong dự án của bạn và chỉ cần thêm các mã này

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

bây giờ nhập tệp hoc.js nơi bạn muốn sử dụng, bây giờ thay vì gói bằng phần tử div, chúng ta có thể gói bằng hoc.

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

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

Mặc dù mã này có thể trả lời câu hỏi, việc cung cấp ngữ cảnh bổ sung về cách thức và / hoặc lý do giải quyết vấn đề sẽ cải thiện giá trị lâu dài của câu trả lời. Đọc này .
Chaieshwar Inde

Các chức năng mà bạn đang nói về, được gọi là HOC trong Reacjs. có nghĩa là props.children
Fazal

4

Có một quy tắc trong phản ứng rằng một biểu thức JSX phải có chính xác một phần tử ngoài cùng.

Sai lầm

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

chính xác

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

1

React 16 nhận được sự trở lại của bạn dưới dạng một mảng để nó được bao bọc bởi một phần tử như div.

Cách tiếp cận sai

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

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

    );
}

Phương pháp tiếp cận đúng (Tất cả các yếu tố trong một div hoặc yếu tố khác bạn đang sử dụng)

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

Các thành phần phản ứng phải bao bọc trong một thùng chứa, đó có thể là bất kỳ thẻ nào, ví dụ: "<div> .. </ div>"

Bạn có thể kiểm tra phương thức kết xuất của ReactCSSTransitiongroup


0

Nhập xem và bọc trong View. Gói trong một divkhông làm việc cho tôi.

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

2
đó là bởi vì bạn đang sử dụng phản ứng bản địa.
Nick H247

Và các mảnh cũng có sẵn trong React Native, vì vậy Viewđây không thực sự là giải pháp tốt nhất.
Emile Bergeron

0

Không hợp lệ: Không chỉ các phần tử con

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

Hợp lệ: Phần tử gốc dưới phần tử con

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

Vui lòng tránh trả lời kiểu "tôi cũng vậy" hoặc lặp lại cùng một giải pháp, trừ khi bạn có điều gì đó liên quan để thêm vào nó.
Emile Bergeron

-1

Dành cho các nhà phát triển Rect-Native. Tôi gặp lỗi này trong khi renderItem trong FlatList. Tôi đã có hai thành phần văn bản. Tôi đã sử dụng chúng như dưới đây

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

Nhưng sau khi tôi đặt các thành phần này trong Inside View, nó hoạt động với tôi.

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

Bạn có thể đang sử dụng các thành phần khác nhưng đưa chúng vào View có thể hiệu quả với bạn.


Các mảnh vỡ cũng có sẵn trong React Native, vì vậy Viewđây không thực sự là giải pháp tốt nhất.
Emile Bergeron

-1

Tôi nghĩ rằng sự phức tạp cũng có thể xảy ra khi cố gắng lồng nhiều Div trong câu lệnh return. Bạn có thể muốn làm điều này để đảm bảo các thành phần của bạn hiển thị dưới dạng các phần tử khối.

Đây là một ví dụ về kết xuất chính xác một vài thành phần, sử dụng nhiều div.

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

-1

Tôi đã có một vấn đề tạo ra lỗi này không phải là tất cả cùng nhau rõ ràng.

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

Và đây là bản sửa lỗi ...

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

Đi hình. Thông tin được chia sẻ ở đây trong trường hợp những người khác nhấn vết sưng này. Rõ ràng, bạn không thể có một tên lớp phần tử giống như tên hàm React của nó.


Đo không phải sự thật. Nó thậm chí còn là mặc định trong mẫu Reactbox. Một cái gì đó khác phải có xung đột với tên lớp này.
Emile Bergeron
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.