Analysefehler: Benachbarte JSX-Elemente müssen in ein umschließendes Tag eingeschlossen werden

467

Ich versuche, meine React.jsApp so einzurichten, dass sie nur gerendert wird, wenn eine von mir festgelegte Variable ist true.

Die Art und Weise, wie meine Renderfunktion eingerichtet ist, sieht folgendermaßen aus:

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

Grundsätzlich ist der wichtige Teil hier der if(this.state.submitted==false)Teil (ich möchte, dass diese divElemente angezeigt werden, wenn die übermittelte Variable auf gesetzt ist false).

Aber wenn ich das ausführe, bekomme ich den Fehler in der Frage:

Nicht erfasster Fehler: Analysefehler: Zeile 38: Benachbarte JSX-Elemente müssen in ein umschließendes Tag eingeschlossen werden

Was ist das Problem hier? Und womit kann ich diese Arbeit machen?

user1072337
quelle
3
stackoverflow.com/questions/25034994/… Die anderen Leute hier sagen Ihnen nur, dass Sie ein übergeordnetes Element verwenden sollen, aber das kann unnötig sein. Diese ältere Version Ihrer Frage hat eine interessante Antwort mit Arrays.
Miau

Antworten:

636

Sie sollten Ihre Komponente zwischen ein umschließendes Tag setzen. Dies bedeutet:

// WRONG!

return (  
    <Comp1 />
    <Comp2 />
)

Stattdessen:

// Correct

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

Bearbeiten: Per Joe Clay's Kommentar zur Fragment-API

// More Correct

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

// Short syntax

return (
    <>
       <Comp1 />
       <Comp2 />
    </>
)
wdanxna
quelle
4
Was ist, wenn ich 2 Zeilen zusammen in einer Tabelle drucke? Wie kann ich <tr> einpacken?
Jose
235

Es ist spät, diese Frage zu beantworten, aber ich dachte, es wird die Erklärung ergänzen.

Dies geschieht, weil an einer beliebigen Stelle in Ihrem Code zwei Elemente gleichzeitig zurückgegeben werden.

z.B

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

Es sollte in ein übergeordnetes Element eingeschlossen werden. z.B

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


Detailliertere Erklärung

Ihr unten stehender jsxCode wird transformiert

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

das sehr gut finden

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

Aber wenn du das tust

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

dies wird in dieses umgewandelt (nur zur Veranschaulichung, tatsächlich werden Sie bekommen 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'
        )
    }
  }]);

Im obigen Code können Sie sehen, dass Sie versuchen, zweimal von einem Methodenaufruf zurückzukehren, was offensichtlich falsch ist.

Bearbeiten - Neueste Änderungen in React 16 und eigenen Stationen:

Wenn Sie kein zusätzliches div zum Umschließen hinzufügen möchten und mehr als eine untergeordnete Komponente zurückgeben möchten, können Sie damit arbeiten React.Fragments.

React.Fragments sind etwas schneller und haben weniger Speicherbedarf (kein zusätzlicher DOM-Knoten erforderlich, weniger überfüllter DOM-Baum).

zB (In Reaktion 16.2.0)

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

oder

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

oder

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

Das React-Element muss nur ein Element zurückgeben. Sie müssen beide Tags mit einem anderen Element-Tag umschließen.

Ich kann auch sehen, dass Ihre Renderfunktion nichts zurückgibt. So sollte Ihre Komponente aussehen:

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

Beachten Sie auch, dass Sie keine ifAnweisungen innerhalb eines zurückgegebenen Elements verwenden können:

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 />
    }
},
Matan Gubkin
quelle
Dies behebt das Problem nicht mit dem "Wenn". Wenn ich das "Wenn" innerhalb der Renderfunktion entferne, funktioniert es einwandfrei.
user1072337
1
Beachten Sie, dass Sie keine Anweisungen innerhalb eines neu abgestimmten Elements verwenden können. Schau dir meine aktualisierte Antwort an
Matan Gubkin
99

Wenn Sie es nicht in ein anderes Div einschließen möchten, wie andere Antworten vorgeschlagen haben, können Sie es auch in ein Array einschließen, und es funktioniert.

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

Es kann geschrieben werden als:

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

Bitte beachten Sie, dass oben eine Warnung generiert wird: Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of 'YourComponent'.

Dies kann durch Hinzufügen eines keyAttributs zu den Komponenten behoben werden. Wenn Sie diese manuell hinzufügen, fügen Sie es wie folgt hinzu:

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

Hier finden Sie weitere Informationen zu Schlüsseln: Zusammensetzung vs. Vererbung

Neal
quelle
7
Ich habe es versucht und es gibt mir einen Fehler. Ein gültiges React-Element (oder null) muss zurückgegeben werden. Möglicherweise haben Sie undefiniert, ein Array oder ein anderes ungültiges Objekt zurückgegeben.
Prasadmsvs
3
@prasadmsvs +1 invariant.js: 39 Nicht erfasste invariante Verletzung: CommitFilter.render (): Eine gültige ReactComponent muss zurückgegeben werden. Möglicherweise haben Sie undefiniert, ein Array oder ein anderes ungültiges Objekt zurückgegeben.
Svetlana Ivanova
1
Dies ist eine großartige Lösung für Zeiten, in denen Sie ein Wrapper-Element vermeiden müssen / möchten!
Bloudermilk
2
@aaaaaa Dies ist aufgrund der Funktionsweise des aktuellen React-Abgleichs nicht möglich. Es ist ein Stapel und die Abstimmung erfolgt rekursiv. In React 16 ist dies behoben, und Sie können jetzt ein Array zurückgeben.
Natnai
1
github.com/iamdustan/tiny-react-renderer ist ein ausgezeichnetes Repository, das jeder Reaktionsentwickler lesen sollte. Sobald Sie dies tun, sollte Ihnen sofort klar werden, warum die aktuelle Implementierung von react es nicht erlaubt, mehrere Kinder zurückzugeben.
Natnai
49

Das Problem

Analysefehler: Benachbarte JSX-Elemente müssen in ein umschließendes Tag eingeschlossen werden

Dies bedeutet, dass Sie versuchen, mehrere Geschwister-JSX-Elemente auf falsche Weise zurückzugeben. Denken Sie daran, dass Sie nicht HTML schreiben, sondern JSX! Ihr Code wird von JSX in JavaScript übertragen. Zum Beispiel:

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

wird transpiliert in:

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

Sofern Sie mit der Programmierung im Allgemeinen noch nicht vertraut sind, wissen Sie bereits, dass Funktionen / Methoden (jeder Sprache) eine beliebige Anzahl von Parametern annehmen, aber immer nur einen Wert zurückgeben. Angesichts dessen können Sie wahrscheinlich feststellen, dass ein Problem auftritt, wenn Sie versuchen, mehrere Geschwisterkomponenten basierend auf der Funktionsweise zurückzugeben createElement(). Es werden nur Parameter für ein Element verwendet und diese zurückgegeben. Daher können wir nicht mehrere Elemente aus einem Funktionsaufruf zurückgeben.


Also, wenn Sie sich jemals gefragt haben, warum das funktioniert ...

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

aber nicht das ...

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

es ist , weil in dem ersten Schnipsel, beide <p>-Elemente Teile sind childrender <div>-elementigen. Wenn sie Teil von sind children, können wir eine unbegrenzte Anzahl von Geschwisterelementen ausdrücken. Schauen Sie sich an, wie sich dies auswirken würde:

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

Lösungen

Abhängig davon, welche Version von React Sie ausführen, haben Sie einige Optionen, um dies zu beheben:

  • Verwenden Sie Fragmente (Reagieren Sie nur auf Version 16.2 +!)

    Ab React v16.2 unterstützt React Fragmente , eine knotenlose Komponente, die ihre untergeordneten Elemente direkt zurückgibt.

    Das Zurückgeben der untergeordneten Elemente in einem Array (siehe unten) hat einige Nachteile:

    • Kinder in einem Array müssen durch Kommas getrennt werden.
    • Kinder in einem Array müssen einen Schlüssel haben, um die Schlüsselwarnung von React zu verhindern.
    • Zeichenfolgen müssen in Anführungszeichen gesetzt werden.

    Diese werden bei der Verwendung von Fragmenten eliminiert. Hier ist ein Beispiel für Kinder, die in ein Fragment eingewickelt sind:

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

    welche Entzucker in:

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

    Beachten Sie, dass für das erste Snippet Babel v7.0 oder höher erforderlich ist.


  • Geben Sie ein Array zurück (Reagieren Sie nur auf Version 16.0 +!)

    Ab React v16 können React Components Arrays zurückgeben. Dies ist anders als in früheren Versionen von React, in denen Sie gezwungen waren, alle Geschwisterkomponenten in eine übergeordnete Komponente zu packen.

    Mit anderen Worten, Sie können jetzt Folgendes tun:

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

    dies überträgt sich in:

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

    Beachten Sie, dass das oben Gesagte ein Array zurückgibt. Arrays sind seit React Version 16 und höher gültige React Elements. In früheren Versionen von React sind Arrays keine gültigen Rückgabeobjekte!

    Beachten Sie außerdem, dass Folgendes ungültig ist (Sie müssen ein Array zurückgeben):

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

  • Wickeln Sie die Elemente in ein übergeordnetes Element ein

    Die andere Lösung besteht darin, eine übergeordnete Komponente zu erstellen, die die Geschwisterkomponenten in ihre einschließt children. Dies ist bei weitem die häufigste Methode, um dieses Problem zu beheben, und funktioniert in allen Versionen von React.

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

    Hinweis: Schauen Sie oben in dieser Antwort noch einmal nach, um weitere Details zu erfahren und wie sich dies auswirkt .

Chris
quelle
@Grievoushead, nicht für Komponenten, nein. Nur für Kinder.
Chris
1
Nettes, behobenes Problem für mich.
Sohan
1
Vielen Dank an Chris, dass er sich die Zeit genommen hat, andere Lösungen zu erklären!
Marvel Moe
on React v16.4das erste Beispiel funktioniert nicht mit : <>, nur <React.Fragment>:(
vsync
@vsync Die Unterstützung für diese Syntax hängt von Ihrer Gebäudeumgebung ab. Ich bin mir nicht sicher, ob Babel es noch unterstützt und wenn ja, welche Version.
Chris
22

In Reaktion 16.0.0 können wir mehrere Komponenten aus dem Rendering als Array zurückgeben.

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

In 16.4.0 können wir mehrere Komponenten aus dem Rendering in einem Fragment-Tag zurückgeben. Fragment

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

Future React Sie können diese Kurzsyntax verwenden. (Viele Tools unterstützen es noch nicht, daher möchten Sie möglicherweise explizit schreiben, <Fragment>bis das Tool aufholt.)

return (
<>
    <Comp1 />
    <Comp2 />
</>)
Morris S.
quelle
1
Sie haben ein ,zwischen den Komponenten vergessen . Da es sich um ein Array handelt, müssen Sie jedes Element darin trennen.
Chris
Es gibt keine <Fragment>, es ist <React.Fragment>. sagt so in Ihrem eigenen Link
vsync
2
Wenn Sie destrukturieren, import React { Fragment } from 'react';dann verwenden Sie es so<Fragment >
Morris S
7

Wenn Sie Ihre Komponente nicht umschließen, können Sie sie wie unten beschrieben schreiben.

Anstatt:

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

Sie können dies schreiben:

return[(
 <Comp1 />
),
(
<Comp2 />
) ];
Ronak Ganatra
quelle
6

Es ist sehr einfach, ein übergeordnetes Element div zu verwenden, um das gesamte Element zu verpacken, oder wir können das HOC-Konzept (Higher Order Component) verwenden, das sehr nützlich ist, um js-Anwendungen zu reagieren

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

oder ein anderer bester Weg ist HOC, es ist sehr einfach, nicht sehr kompliziert. Fügen Sie einfach eine Datei hoc.js in Ihr Projekt ein und fügen Sie einfach diese Codes hinzu

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

Importieren Sie jetzt die Datei hoc.js, die Sie verwenden möchten. Statt mit dem div-Element zu umbrechen, können wir jetzt mit hoc umbrechen.

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

    render() {
      return (
    <Hoc>
        <div>foo</div>
        <div>bar</div>
    </Hoc>
      );
    }
Fazal
quelle
Während dieser Code die Frage möglicherweise beantwortet, würde die Bereitstellung eines zusätzlichen Kontexts darüber, wie und / oder warum das Problem gelöst wird, den langfristigen Wert der Antwort verbessern. Lesen Sie dies .
Shanteshwar Inde
Die Funktionalität, über die Sie sprechen, dh HOC in Reactjs genannt. bedeutet props.children
Fazal vor
4

Es gibt eine Regel in der Reaktion, dass ein JSX-Ausdruck genau ein äußerstes Element haben muss.

falsch

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

richtig

const para = (
    <div>
        <p></p>
        <p></p>
    </div>
);
Khandelwal-manik
quelle
1

React 16 erhält Ihre Rückgabe als Array, sodass es von einem Element wie div umschlossen werden sollte.

Falscher Ansatz

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

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

    );
}

Richtiger Ansatz (Alle Elemente in einem Div oder einem anderen Element, das Sie verwenden)

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

            <button className="btn btn-primary" onClick={()=>this.addTodo(this.state.value)}>Submit</button>
        </div>
    );
}
Abdul Moiz
quelle
1

Reaktionskomponenten müssen in einem einzelnen Container verpackt sein. Dies kann ein beliebiges Tag sein, z. B. "<div> .. </ div>".

Sie können die Rendermethode von ReactCSSTransitionGroup überprüfen

Shivprasad P.
quelle
0

Ansicht importieren und einbinden View. Das Einwickeln in a divhat bei mir nicht funktioniert.

import { View } from 'react-native';
...
    render() {
      return (
        <View>
          <h1>foo</h1>
          <h2>bar</h2>
        </View>
      );
    }
Ocko
quelle
2
Das liegt daran, dass Sie React Native verwenden.
Nick H247
Und Fragmente sind auch in React Native verfügbar, sodass a Viewnicht wirklich die beste Lösung ist.
Emile Bergeron
0

Ungültig: Nicht nur untergeordnete Elemente

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

Gültig: Stammelement unter untergeordneten Elementen

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>
        )
    }
KARTHIKEYAN.A
quelle
Bitte vermeiden Sie, dass "ich auch" Antworten eingibt oder dieselbe Lösung wiederholt, es sei denn, Sie haben etwas Relevantes hinzuzufügen .
Emile Bergeron
-1

Für Rect-Native-Entwickler. Dieser Fehler tritt beim Rendern von Item in FlatList auf. Ich hatte zwei Textkomponenten. Ich habe sie wie unten benutzt

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

Aber nachdem ich diese zwei Inside View-Komponenten eingesetzt hatte, funktionierte es für mich.

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

Möglicherweise verwenden Sie andere Komponenten, aber das Einfügen in View kann für Sie hilfreich sein.

Gurjinder Singh
quelle
Fragmente sind auch in React Native verfügbar, daher Viewist a nicht wirklich die beste Lösung.
Emile Bergeron
-1

Ich denke, die Komplikation kann auch auftreten, wenn versucht wird, mehrere Divs in der return-Anweisung zu verschachteln. Möglicherweise möchten Sie dies tun, um sicherzustellen, dass Ihre Komponenten als Blockelemente gerendert werden.

Hier ist ein Beispiel für das korrekte Rendern einiger Komponenten mit mehreren Divs.

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

Ich hatte ein Problem, das diesen Fehler verursachte, der insgesamt nicht offensichtlich war.

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

Und hier war die Lösung ...

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

Stelle dir das vor. Hier geteilte Informationen für den Fall, dass andere diese Beule treffen. Anscheinend können Sie keinen Elementklassennamen haben, der mit dem Namen der übergeordneten React-Funktion identisch ist.

zipzit
quelle
Das ist nicht wahr. Dies ist sogar die Standardeinstellung in der Vorlage "Codesandbox React". Etwas anderes muss mit diesem Klassennamen in Konflikt geraten sein.
Emile Bergeron