javascript - Parse-feil: Tilstøtende JSX-elementer må omsluttes av en omgivende tagg


Jeg prøver å sette opp min React.js-app slik at den bare rendres hvis en variabel jeg har satt er true.

Måten render-funksjonen min er satt opp på ser slik ut:

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

I utgangspunktet er den viktige delen her if(this.state.submitted==false)-delen (jeg vil at disse div-elementene skal vises når variabelen submitted er satt til false).

Men når jeg kjører dette, får jeg feilen som er nevnt i spørsmålet:

Ufanget feil: Parsefeil: Linje 38: Nabo-JSX-elementer må være pakket inn i en omsluttende tag

Hva er problemet her? Og hva kan jeg bruke for å få dette til å fungere?

Svar #1

Du bør legge komponenten din mellom en omsluttende tag, noe som betyr:

// WRONG!

return (  
    <Comp1 />
    <Comp2 />
)

I stedet :

// Correct

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

Rediger: I henhold til Joe Clays kommentar om Fragments API

// More Correct

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

// Short syntax

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

Svar #2

Det er sent å svare på dette spørsmålet, men jeg trodde det ville legge til forklaringen.

Det skjer fordi hvor som helst i koden din returnerer du to elementer samtidig.

f.eks.

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

Det bør pakkes inn i et foreldre-element. f.eks

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

Mer detaljert forklaring

Koden din nedenfor jsx blir omdannet

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

inn i dette

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

Men hvis du gjør dette

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

dette blir konvertert til dette (Bare for illustrasjonsformål, egentlig vil du få feil : Tilstøtende JSX-elementer må være pakket inn i en omsluttende tag)

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

I koden ovenfor kan du se at du prøver å returnere to ganger fra et metodekall, noe som åpenbart er feil.

Rediger- Siste endringer i React 16 og videre:

Hvis du ikke vil legge til en ekstra div for å pakke inn og ønsker å returnere mer enn ett barnekomponent, kan du bruke React.Fragments.

React.Fragments (<React.Fragments>) er litt raskere og bruker mindre minne (ingen behov for å opprette en ekstra DOM-node, mindre rotete DOM-tre).

f.eks (I React 16.2.0)

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

eller

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

eller

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

Svar #3

React-elementet må returnere bare ett element. Du må omslutte begge taggene dine med en annen elementtagg.

Jeg kan også se at render-funksjonen din ikke returnerer noe. Slik bør komponenten din se ut:

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

Merk også at du ikke kan bruke if-setninger inne i et returnert element:

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

Svar #4

Hvis du ikke vil pakke det inn i en annen div som andre svar har foreslått, kan du også pakke det inn i en array, og det vil fungere.

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

Det kan skrives som:

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

Vennligst merk at ovenstående vil generere en advarsel: Advarsel: Hvert barn i en array eller iterator bør ha en unik "key"-prop. Sjekk render-metoden til 'YourComponent'.

Dette kan fikses ved å legge til et key-attributt til komponentene. Hvis du legger til disse manuelt, gjør det slik:

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

Her er litt mer informasjon om nøkler: Sammensetning vs Arv

Svar #5

Problemet

Parsefeil: Tilstøtende JSX-elementer må være innpakket i en omsluttende tag

Dette betyr at du prøver å returnere flere søskende JSX-elementer på en feil måte. Husk at du ikke skriver HTML, men JSX! Koden din blir transpilt fra JSX til JavaScript. For eksempel:

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

vil bli transpilert til:

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

Med mindre du er ny innen programmering generelt, vet du allerede at funksjoner/metoder (i ethvert språk) kan ta et hvilket som helst antall parametere, men alltid bare returnere én verdi. Gitt det, kan du sannsynligvis se at det oppstår et problem når man prøver å returnere flere søsterkomponenter, basert på hvordan createElement() fungerer; den tar bare parametere for ett element og returnerer det. Derfor kan vi ikke returnere flere elementer fra et enkelt funksjonskall.

Så hvis du noen gang har lurt på hvorfor dette fungerer...

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

men ikke dette...

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

det er fordi i det første utdraget, er begge <p>-elementene en del av children til <div>-elementet. Når de er en del av children kan vi uttrykke et ubegrenset antall søsterelementer. Se hvordan dette vil transpileres:

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

Løsninger

Avhengig av hvilken versjon av React du bruker, har du noen alternativer for å håndtere dette:

  • Bruk fragmenter (kun React v16.2+)

    Fra og med React v16.2, har React støtte for Fragments, som er en komponent uten egen node som returnerer sine barn direkte.

    Å returnere barna i et array (se nedenfor) har noen ulemper:

    • Barn i et array må skilles med komma.
    • Barn i et array må ha en nøkkel for å forhindre Reacts nøkkelvarsling.
    • Strenger må omsluttes av anførselstegn.

    Disse elimineres fra bruken av fragmenter. Her er et eksempel på barn pakket inn i et fragment:

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

    som omdannes til sukkerfri versjon:

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

    Merk at den første kodesnutten krever Babel v7.0 eller høyere.

  • Returner et array (kun React v16.0+)

    Fra og med React v16 kan React-komponenter returnere arrays. Dette er ulikt tidligere versjoner av React der du var nødt til å pakke alle søsterkomponenter inn i en overordnet komponent.

    Med andre ord, du kan nå gjøre:

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

    dette transpilerer til:

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

    Merk at ovennevnte returnerer et array. Arrays er gyldige React-elementer siden React versjon 16 og senere. For tidligere versjoner av React er ikke arrays gyldige returobjekter!

    Merk også at følgende er ugyldig (du må returnere et array):

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

  • Pakk elementene inn i et overordnet element

    Den andre løsningen innebærer å lage en overordnet komponent som omslutter søsterkomponentene i sine children. Dette er langt den vanligste måten å håndtere dette problemet på, og fungerer i alle versjoner av React.

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

    Merk: Se igjen på toppen av dette svaret for mer detaljer og hvordan dette transpileres.

Svar #6

React 16.0.0 kan vi returnere flere komponenter fra render som et array.

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

React 16.2.0 > vi kan returnere flere komponenter fra render i en Fragment-tagg. Fragment

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

React 16.2.0 > kan du bruke denne forkortede syntaksen. (noen eldre verktøyversjoner støtter det ikke, så du vil kanskje uttrykkelig skrive <Fragment> inntil verktøyene tar igjen.)

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

Relaterte artikler