Errore di analisi: gli elementi JSX adiacenti devono essere racchiusi in un tag allegato


467

Sto provando a configurare la mia React.jsapp in modo che esegua il rendering solo se è una variabile che ho impostato true.

Il modo in cui è impostata la mia funzione di rendering è simile a:

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

Fondamentalmente, la parte importante qui è la if(this.state.submitted==false)parte (voglio che questi divelementi vengano visualizzati quando la variabile inviata è impostata su false).

Ma quando eseguo questo, ottengo l'errore nella domanda:

Errore non rilevato: errore di analisi: riga 38: gli elementi JSX adiacenti devono essere racchiusi in un tag allegato

Qual è il problema qui? E cosa posso usare per farlo funzionare?


3
stackoverflow.com/questions/25034994/… Le altre persone qui ti stanno solo dicendo di usare un elemento genitore, ma potrebbe non essere necessario. Questa versione precedente della tua domanda ha una risposta interessante usando gli array.
Meow,

Risposte:


637

Devi inserire il tuo componente tra un tag che racchiude, il che significa:

// WRONG!

return (  
    <Comp1 />
    <Comp2 />
)

Anziché:

// Correct

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

Modifica: commento di Per Joe Clay sull'API Fragments

// More Correct

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

// Short syntax

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

4
Cosa succede se sto stampando 2 righe insieme in una tabella. Come posso avvolgere <tr>?
Jose

235

È tardi per rispondere a questa domanda ma ho pensato che aggiungerà alla spiegazione.

Sta succedendo perché in qualsiasi punto del tuo codice stai restituendo due elementi contemporaneamente.

per esempio

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

Dovrebbe essere racchiuso in un elemento padre . per esempio

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


Spiegazione più dettagliata

Il jsxcodice seguente viene trasformato

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

in questo

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

Ma se lo fai

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

questo viene convertito in questo (solo a scopo illustrativo, in realtà otterrai 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'
        )
    }
  }]);

Nel codice sopra puoi vedere che stai provando a tornare due volte da una chiamata del metodo, il che è ovviamente sbagliato.

Modifica - Ultime modifiche in React 16 e reparti propri:

Se non si desidera aggiungere ulteriori div da avvolgere e si desidera restituire più di un componente figlio, è possibile utilizzarlo React.Fragments.

React.Fragments sono un po 'più veloci e hanno un minore utilizzo della memoria (non è necessario creare un nodo DOM aggiuntivo, albero DOM meno ingombrante).

ad es. (In React 16.2.0)

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

o

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

o

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

115

L'elemento React deve restituire solo un elemento. Dovrai avvolgere entrambi i tag con un altro tag element.

Vedo anche che la tua funzione di rendering non sta restituendo nulla. Ecco come dovrebbe apparire il tuo componente:

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

Si noti inoltre che non è possibile utilizzare le ifistruzioni all'interno di un elemento restituito:

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

questo non risolve il problema con "if"; Se rimuovo il "if" all'interno della funzione di rendering, funziona benissimo.
user1072337

1
si noti che non è possibile utilizzare se statments all'interno di un elemento risintonizzato. guarda la mia risposta aggiornata
Matan Gubkin,

99

Se non vuoi avvolgerlo in un altro div come suggerito da altre risposte, puoi anche avvolgerlo in un array e funzionerà.

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

Può essere scritto come:

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

Si noti che quanto sopra genererà un avviso: Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of 'YourComponent'.

Questo può essere risolto aggiungendo un keyattributo ai componenti, se aggiungendoli manualmente aggiungilo come:

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

Ecco alcune ulteriori informazioni sui tasti: Composizione vs Ereditarietà


7
Ho provato questo e mi dà un errore. È necessario restituire un elemento React (o null) valido. Potresti aver restituito un indefinito, un array o qualche altro oggetto non valido.
prasadmsvs,

3
@prasadmsvs +1 invariant.js: 39 Violazione invariante non rilevata: CommitFilter.render (): deve essere restituito un ReactComponent valido. Potresti aver restituito un indefinito, un array o qualche altro oggetto non valido.
Svetlana Ivanova,

1
Questa è un'ottima soluzione per i momenti in cui è necessario / si desidera evitare un elemento wrapper!
Bloudermilk,

2
@aaaaaa non è possibile a causa del modo in cui funziona il riconciliatore React corrente. È uno stack e la riconciliazione viene eseguita in modo ricorsivo. In React 16 questo è stato risolto e ora puoi restituire un array.
natnai

1
github.com/iamdustan/tiny-react-renderer è un repository eccellente che ogni sviluppatore di reazioni dovrebbe leggere. Una volta fatto, ti dovrebbe essere immediatamente chiaro il motivo per cui l'attuale implementazione di reagire non consente il ritorno di più figli.
natnai

49

Il problema

Errore di analisi: gli elementi JSX adiacenti devono essere racchiusi in un tag allegato

Ciò significa che stai cercando di restituire più elementi JSX di pari livello in modo errato. Ricorda che non stai scrivendo HTML, ma JSX! Il tuo codice viene trasferito da JSX in JavaScript. Per esempio:

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

sarà traspilato in:

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

A meno che non siate nuovi alla programmazione in generale, sapete già che funzioni / metodi (di qualsiasi lingua) accettano un numero qualsiasi di parametri ma restituiscono sempre solo un valore. Detto questo, è probabile che si verifichi un problema quando si tenta di restituire più componenti di pari livello in base al createElement()funzionamento; prende solo i parametri per un elemento e lo restituisce. Quindi non possiamo restituire più elementi da una chiamata di funzione.


Quindi se ti sei mai chiesto perché funziona ...

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

ma non questo ...

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

è perché nel primo frammento, entrambi <p>-Elementi fanno parte childrendel <div>-element. Quando ne fanno parte children, possiamo esprimere un numero illimitato di elementi di pari livello. Dai un'occhiata a come questo si verificherebbe:

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

soluzioni

A seconda della versione di React in esecuzione, sono disponibili alcune opzioni per risolvere questo problema:

  • Usa frammenti (solo React v16.2 +!)

    A partire da React v16.2, React ha il supporto per Fragments che è un componente senza nodi che restituisce direttamente i suoi figli.

    Restituire i figli in un array (vedi sotto) presenta alcuni svantaggi:

    • I bambini in un array devono essere separati da virgole.
    • I bambini in un array devono avere una chiave per impedire l'avvertimento della chiave di React.
    • Le stringhe devono essere racchiuse tra virgolette.

    Questi vengono eliminati dall'uso di frammenti. Ecco un esempio di bambini avvolti in un frammento:

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

    che riduce gli zuccheri in:

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

    Tieni presente che il primo frammento richiede Babel v7.0 o versione successiva.


  • Restituisce un array (solo React v16.0 +!)

    A partire da React v16, React Components può restituire array. Ciò è diverso dalle versioni precedenti di React in cui sei stato costretto a avvolgere tutti i componenti fratelli in un componente padre.

    In altre parole, ora puoi fare:

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

    questo si traduce in:

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

    Si noti che quanto sopra restituisce un array. Le matrici sono elementi React validi dalla versione 16 di React e successive. Per le versioni precedenti di React, le matrici non sono oggetti di ritorno validi!

    Si noti inoltre che quanto segue non è valido (è necessario restituire un array):

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

  • Avvolgi gli elementi in un elemento padre

    L'altra soluzione prevede la creazione di un componente padre che avvolge i componenti di pari livello al suo interno children. Questo è di gran lunga il modo più comune per affrontare questo problema e funziona in tutte le versioni di React.

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

    Nota: dai un'occhiata di nuovo nella parte superiore di questa risposta per maggiori dettagli e come questo si traspone .


@Grievoushead, non per componenti, no. Solo per bambini.
Chris,

1
Bello, problema risolto per me.
Sohan,

1
Grazie Chris per aver dedicato del tempo a spiegare altre soluzioni!
Marvel Moe,

su React v16.4il primo esempio non funziona usando <><React.Fragment>
:,

@vsync il supporto per quella sintassi varia a seconda dell'ambiente di costruzione. Non sono sicuro se Babel lo supporti ancora e, in tal caso, quale versione.
Chris,

22

Reagire 16.0.0 possiamo restituire più componenti da render come un array.

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

Reagire 16.4.0 possiamo restituire più componenti dal rendering in un tag Fragment. Frammento

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

Future React sarai in grado di usare questa sintassi abbreviata. (molti strumenti non lo supportano ancora, quindi potresti voler scrivere esplicitamente <Fragment>fino a quando gli strumenti non raggiungono.)

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

1
Hai dimenticato una ,tra i componenti. È un array, quindi è necessario separare ogni elemento al suo interno.
Chris,

Non c'è <Fragment>, lo è <React.Fragment>. dice così nel tuo link
vsync il

2
Se stai distruggendo, import React { Fragment } from 'react';lo usi in questo modo<Fragment >
Morris S,

7

Se non avvolgi il componente, puoi scriverlo come indicato di seguito.

Invece di:

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

puoi scrivere questo:

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

6

è molto semplice che possiamo usare un div dell'elemento genitore per avvolgere tutti gli elementi o possiamo usare il concetto di componente di ordine superiore (HOC), cioè molto utile per le applicazioni di reazione js

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

o un altro modo migliore è HOC è molto semplice, non molto complicato, basta aggiungere un file hoc.js nel progetto e semplicemente aggiungere questi codici

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

ora importa il file hoc.js dove vuoi usare, ora invece di avvolgere con l'elemento div possiamo avvolgere con hoc.

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

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

Sebbene questo codice possa rispondere alla domanda, fornire un contesto aggiuntivo riguardo a come e / o perché risolve il problema migliorerebbe il valore a lungo termine della risposta. Leggi questo .
Shanteshwar Inde

Funzionalità di cui stai parlando, ad esempio chiamata HOC in reazioni. significa props.children
Fazal

4

C'è una regola in reazione che un'espressione JSX deve avere esattamente un elemento più esterno.

sbagliato

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

corretta

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

1

React 16 ottiene il tuo ritorno come un array, quindi dovrebbe essere racchiuso da un elemento come div.

Approccio sbagliato

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

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

    );
}

Approccio giusto (tutti gli elementi in un div o in un altro elemento in uso)

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

I componenti di React devono essere confezionati in un unico contenitore, che può essere qualsiasi tag, ad esempio "<div> .. </ div>"

Puoi controllare il metodo di rendering di ReactCSSTransitionGroup


0

Importa vista e avvolgi View. L'avvolgimento in a divnon ha funzionato per me.

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

2
questo perché stai usando reagire nativo.
Nick H247,

E i frammenti sono disponibili anche in React Native, quindi Viewnon è davvero la soluzione migliore.
Emile Bergeron,

0

Non valido: non solo elementi figlio

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

Valido: elemento radice sotto elementi figlio

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

Per favore, evita le risposte tipo "me too" o ripeti la stessa soluzione, a meno che tu non abbia qualcosa di rilevante da aggiungere ad essa.
Emile Bergeron,

-1

Per gli sviluppatori Rect-Native. Riscontro questo errore mentre renderingItem in FlatList. Ho avuto due componenti di testo. Li stavo usando come di seguito

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

Ma dopo aver messo questi rimorchi Inside View Components ha funzionato per me.

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

È possibile che tu stia utilizzando altri componenti, ma metterli in View potrebbe funzionare per te.


I frammenti sono disponibili anche in React Native, quindi Viewnon è davvero la soluzione migliore.
Emile Bergeron,

-1

Penso che la complicazione possa verificarsi anche quando si tenta di annidare Div multipli all'interno dell'istruzione return. È possibile che ciò avvenga per garantire il rendering dei componenti come elementi di blocco.

Ecco un esempio di rendering corretto di un paio di componenti, utilizzando più div.

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

-1

Ho avuto un problema che ha generato questo errore che non era del tutto ovvio.

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

Ed ecco la soluzione ...

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

Vai a capire. Informazioni condivise qui nel caso in cui altri colpiscano questo dosso. Apparentemente, non puoi avere un nome di classe di elemento uguale al nome della sua funzione genitore React.


Non è vero. È anche il valore predefinito nel modello di React di codesandbox. Qualcos'altro deve essere in conflitto con questo nome di classe.
Emile Bergeron,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.