React: Fügen Sie eine Fragment-API hinzu, um die Rückgabe mehrerer Komponenten aus dem Rendering zu ermöglichen

Erstellt am 2. Sept. 2014  ·  148Kommentare  ·  Quelle: facebook/react


Hinweis der Betreuer:

Wir wissen, dass dies ein Problem ist, und wir wissen genau, welche Probleme gelöst werden können. Wir wollen das auch, aber es ist ein _hartes Problem_ mit unserer aktuellen Architektur. Zusätzliche Kommentare, die den Wunsch nach dieser Funktion äußern, sind nicht hilfreich. Fühlen Sie sich frei, die Ausgabe zu abonnieren (es gibt eine Schaltfläche in der rechten Spalte), aber kommentieren Sie nicht, es sei denn, Sie tragen zur Diskussion bei. „Ich auch“ und „+1“ sind nicht wertvoll, ebensowenig Anwendungsfälle, die bereits in den Kommentaren geschrieben wurden (z. B. wissen wir, dass Sie keine <tr> - oder <dd> -Elemente einfügen können mit <div> ).


Folgendes berücksichtigen:

var ManagePost = React.createClass({

  render: function() {
    var posts = this.props.posts

    var something;
    var somethingelse;

    var row = posts.map(function(post){
      return(
        <div>
          <div className="col-md-8">
          </div>
          <div className="cold-md-4">
          </div>
        </div>
      )
    });

    return (
        {row}
    );
  }

});

Wenn Sie <div></div> in map entfernen, erhalten Sie die folgende Fehlermeldung: _Adjacent XJS elements must be wrapd in an enclosing tag_

Erst wenn ich die umgebenden und ziemlich sinnlosen Divs wieder hinzufüge, wird es ohne Probleme kompiliert. Ich verwende 0.11.1

Wird das angegangen? Es fügt der Seite zusätzliches und wieder - meiner Meinung nach - nutzloses und sinnloses HTML hinzu, das, obwohl es nichts schadet, chaotisch und unprofessionell aussieht. Vielleicht mache ich nur etwas falsch, bitte klärt mich auf, wenn ich es bin.

Hilfreichster Kommentar

Ich denke, wir können das schließen.

Das Zurückgeben von Arrays von Komponenten wird seit React 16 Beta 1 unterstützt, das Sie jetzt ausprobieren können .

Es gibt immer noch einige Einschränkungen (SSR-Unterstützung ist noch nicht bereit), aber wir verfolgen sie in #8854 und werden sie vor der endgültigen Version 16 beheben.

Danke an alle für euer Feedback!

Alle 148 Kommentare

Denn wenn Sie den Wrapper nicht platzieren, wird er folgendermaßen entzuckert:

return React.DOM.div(...)React.DOM.div(...)

Was syntaktisch keinen Sinn macht. Die jsx-Compiler -Seite kann hilfreich sein, wenn Sie eine visuelle Zuordnung benötigen.

Davon abgesehen ist es möglich, dies stattdessen zu [div, div] zu entzuckern. Das ist hart, etwas umstritten und wird in naher Zukunft nicht umgesetzt.

(Ich denke nicht, dass es besonders umstritten ist, aber es fügt Code-Komplexität hinzu und wurde noch nicht gemacht.)

IIRC @syranide hat einige Kommentare dazu

@chenglou Hehe.

Ich hatte vor einiger Zeit ein kurzes Gespräch mit Chenglou darüber, ich neige im Moment nicht wirklich zu der einen oder anderen Seite. Ich sehe viele versteckte Gefahren darin, zuzulassen, dass zusammengesetzte Komponenten mehrere Komponenten zurückgeben, und es bricht viele intuitive Annahmen, aber ich kenne (im Moment) keine bewährten Anwendungsfälle, die offensichtlich davon profitieren würden.

Die Einfachheit, höchstens eine Komponente zurückzugeben, bedeutet, dass es sehr einfach ist, über das, was Sie sehen, nachzudenken, wenn nicht, könnte <table><TableHeader /></table> tatsächlich eine beliebige Anzahl von Zeilen rendern, Sie haben keine andere Möglichkeit, dies zu wissen, als TableHeader zu untersuchen

Ich habe das Gefühl, dass die Möglichkeit, mehrere Komponenten zurückzugeben, nur die Verantwortung für das Umhüllen von Komponenten nach Bedarf von der "Verbundkomponente" auf das verschiebt, was "die Verbundkomponente rendert". Die Komponente, „die eine zusammengesetzte Komponente wiedergibt“, hat oder sollte selten wissen, ob zusammengesetzte Komponenten eingewickelt werden sollen oder nicht, wohingegen Kinder mit größerer Wahrscheinlichkeit Kenntnis von ihren Eltern haben.

Aber vielleicht ist es einfach ein Fall von Entwicklerverantwortung. Es mag für beide gute Anwendungsfälle geben, und wir sollten nur über den unvermeidlichen Missbrauch hinwegsehen.

@sebmarkbage hat wahrscheinlich auch ein paar Kommentare :)

Wir werden diese Syntax wahrscheinlich niemals implizit zulassen. Du bräuchtest einen Wrapper wie

<>
  <div className="col-md-8">
  </div>
  <div className="cold-md-4">
  </div>
</>

ODER

[
  <div className="col-md-8">
  </div>,
  <div className="cold-md-4">
  </div>
]

Allerdings funktioniert auch das nicht. Oft ist es wahrscheinlich das Beste. Es kann verwirrend sein, Komponenten zu verbrauchen, wenn ein untergeordnetes Element möglicherweise in mehrere Elemente erweitert wird.

Aber wirklich, der einzige Grund, warum wir dies derzeit nicht unterstützen, ist, dass es schwer zu implementieren ist. Hoffentlich können wir es irgendwann in der Zukunft unterstützen, aber wahrscheinlich nicht kurzfristig. Es tut uns leid. :/

kann dies keine Auswirkungen auf Dinge wie jquery oder andere Bibliotheken haben, die auf bestimmte Elemente abzielen, wenn Sie also etwas wie $('#id-name').children() tun, Folgendes:

<div id="id-name">
  <div>
    <div class="class-name">
    </div>
  </div>
</div>

die <div> und <div class="class-name"> würden in diesem Fall ausgewählt werden. (wenn ich das richtig verstehe)

Es betrifft auch CSS-Selektoren auf die gleiche Weise, wie @AdamKyle zuvor gepostet hat.

Irgendwelche Updates zu diesem Problem?

Ich verbrachte ein paar Minuten damit zu verstehen, warum meine Komponente nicht funktionierte. Ich habe das Gefühl, dass es irgendwo einen Hinweis geben sollte, vielleicht habe ich ihn übersehen? Vielleicht ist es offensichtlich falsch zu versuchen:

var Optimistic = React.createClass({
  render: function() {
    return ( 
      <h1>{this.props.name} loves React</h1>
      <p>React doesn’t. Idea: sprinkle some divs here and there.</p>
    );
  }
});

React.render(
  <Optimistic name="Peter" />,
  document.getElementById('myContainer')
);

@gabssnake Sie sollten einen JSX-Kompilierungsfehler mit dem Fehler "Benachbarte XJS-Elemente müssen in ein umschließendes Tag eingeschlossen werden" erhalten haben. Haben Sie den Fehler nicht gesehen oder war er in seiner Erklärung nicht klar?

Danke für deine Antwort @spicyj. Nun, ich meinte einen Hinweis in der React-Dokumentation. Ja, die Konsole hat einen Fehler angezeigt, aber die Notwendigkeit des Wrappings ergab für mich zunächst keinen Sinn. Deshalb habe ich gesucht und bin hier gelandet.

Ich hatte diese Schmerzen auch ... besonders schmerzhaft für meinen Designer, um genau zu sein. Es wäre schön, wenn eine Komponente anstelle eines Elements einen Knoten (also eine Knotenliste oder ein Fragment) ausgeben könnte.

render render* nur:

  render: function () {
    return (
      <div className={this.getClassName()}
           style={{
             color: this.props.color,
             backgroundColor: this.props.backgroundColor
           }}>
        {condition ?
          this.renderSomething() :
          this.renderOtherThing()
        }
      </div>
    );
  },

  renderSomething() {
    return (
      <>
        <div className='AboutSection-header'>
          <h1>{this.props.title}</h1>
          {this.props.subtitle &&
            <h4>{this.props.subtitle}</h4>
          }
        </div>,

        {hasChildren &&
          <div className='AboutSection-extra'>
            {this.props.children}
          </div>
        }
      </>
    );
  }

Aber ich sollte wahrscheinlich einfach die Klappe halten und key s verwenden.

@gaearon Das kannst du aber schon machen, du musst vorerst nur ein Array zurückgeben (was aber etwas umständlich ist, ja) ... buuuuut, du kannst das umgehen, ich habe meine eigene <Frag> Komponente gehackt was in ein Array übersetzt wird (überladen React.render ) ... Sie könnten auch return <NoopComp>...</NoopComp>.props.children machen, nehme ich an, wenn Sie Hacks vermeiden wollen.

EDIT: Mein Fehler, ich habe React.createElement überladen, nicht React.render .

Das Problem mit Arrays ist, dass sie unseren Designer zum Stolpern bringen. Brauchen Sie Kommas, explizite Schlüssel.

@gaearon Ja, Sie können die Kommas vorerst mit einer meiner beiden Problemumgehungen vermeiden (wenn Sie eine von beiden für akzeptabel halten) ... aber was meinen Sie mit expliziten Schlüsseln?

Wenn ich die Array-Syntax verwende, muss ich für jedes Element key angeben. Nicht, dass es schwer wäre, aber es fühlt sich unangenehm an, weil ich weiß, dass sie sich nie ändern.

@gaearon Ah ja, ich entscheide mich dafür, diese Warnung vorerst einfach mental zu ignorieren :), wenn du sie wirklich vermeiden willst, kannst du <MyComp children={this.renderWhatever()} /> tun, um sie zu vermeiden ( BEARBEITEN: obwohl du das offensichtlich nicht verwenden kannst Wenn Sie benachbarte Kinder haben, könnten Sie einen Abflachungshelfer gebrauchen ... aber ja).

Ein weiterer Fall, auf den ich mit einem UI-Kit gestoßen bin. Wenn Sie Kinder wie folgt in einen festen scrollbaren Container platzieren:

return (
  <div style={{
    position: fixed
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    overflow-y: scroll;
  }}>
    {this.props.children}
  </div>
);

Die Kinder müssen jetzt als Array übergeben werden, aber wenn eine zusammengesetzte Klasse übergeben wird, muss sie diese Stile auch implementieren, um sie nicht zu beschädigen. Fügt nur eine Ebene der Komplexität hinzu. Aber ich kann vollkommen nachvollziehen, wie komplex die Umstellung sein muss. Ich werfe nur meinen Hut in die Unterstützung.

Ich habe einen anderen Anwendungsfall, den ich hier ausführlich beschrieben habe #3415. Aber ich kann es vorerst umgehen und verstehe, dass es schwer zu implementieren und selten ist.

Ich weiß (noch) nichts über React-Interna, aber ich werfe nur eine Idee ein, wie Sie solche virtuellen übergeordneten Elemente/Fragmente in den DOM:-Kommentaren markieren könnten. Z.B

<A>
    <B></B>
    <Fragment>
        <C></C>
        <D></D>
    </Fragment>
    <E></E>
</A>

würde zu machen

<a>
    <b></b>
    <!--<fragment data-reactid="">-->
        <c></c>
        <d></d>
    <!--</fragment>-->
    <e></e>
</a>

Das bedeutet, dass c und d als Kinder von etw behandelt werden. (einschließlich der verschachtelten Reaktivid, um nicht mit b und e in Konflikt zu geraten). Ich habe gesehen, dass andere Frameworks Kommentare für diese Art von semantischen Jobs "missbrauchen".

@Prinzhorn Ich denke, Sie verwechseln die DOM-Ausgabe möglicherweise mit JSX von React.

Falls es nützlich ist: Der Vorschlag von @Prinzhorn , HTML-Kommentare zu verwenden, um "Fragmentkomponenten" dem DOM zuzuordnen, ist der gleiche Ansatz, den Knockout verwendet. Knockout nennt diese „virtuellen Elemente“.

<!-- ko component: "message-editor" -->
<!-- /ko -->

(aus Knockout-Dokumenten )

Auch ein weiterer Anwendungsfall dafür - die zusätzlichen Verpackungselemente können bei der Verwendung von Flexbox problematisch sein.

@aldendaniels stimme absolut zu, ich bin bereits auf Flexbox-Probleme gestoßen.

Ich bin mit Flexbox mit abhängigen Dropdowns darauf gestoßen. Wo A das erste Dropdown rendern und verwalten würde, gefolgt von B oder C oder D, abhängig vom Wert des Dropdowns von A, die jeweils die entsprechende Anzahl von Dropdowns rendern würden, z

<A>
 <Drop />
 <C><Drop /><Drop /></C>
</A>

A, B, C und D sind zustandslos, also habe ich sie von class B {render(){ this.props }} in function B(props){ return [...]; } geändert.

In diesem Fall spielt es für das übergeordnete Element keine Rolle, dass mehrere untergeordnete Elemente gerendert werden, es geht nur darum, mit meinem CSS umzugehen. Es gibt Dinge, die ich anders machen würde, wenn diese nicht wiederverwendet werden müssten (eine andere Komponente benötigt B, C und D).


Als Alternative vielleicht eine Möglichkeit, es von den Eltern zu lösen? Ich habe keine konkreten Vorstellungen, wie das aussehen könnte.

Ich bin heute auf ein Szenario gestoßen, das meiner Meinung nach ein guter Anwendungsfall für diese Funktion ist: Eine Komponente, die mehrere <script> -Elemente rendert, wobei sie in das <head> -Element der Seite gerendert werden könnte. Jedes Wrapper-Element dort wäre schlecht.

Mein Szenario möchte eine Komponente haben, die für das Rendern des <script> -Tags verantwortlich ist, sowohl für den auf der Seite benötigten Laufzeitcode als auch für ein weiteres <script> -Tag, das die zu verwendenden lokalisierten Zeichenfolgen enthält der Laufzeitcode. Zum Beispiel:

<html>
    <head>
        <script language="runtime.resources.en-us.js"></script>
        <script language="runtime.js"></script>
    </head>
    <body>
    ...
    </body>
</html>

In diesem Fall möchte ich den Code wie folgt verfasst haben:

var RuntimeScripts = require('./Runtime')
...
return (
    <html>
        <head>
            <RuntimeScripts language="en-us" />
        </head>
    </html>
)
...

Ich bin auch auf einige Flexbox-Probleme gestoßen. Nichts, was nicht in CSS gelöst werden kann, aber eine der „Schönheiten“ von Flexbox ist, dass Sie überall weniger „Wrapper“-Elemente benötigen, damit Ihr Layout funktioniert, aber Sie werden immer noch überall Wrapper-Elemente haben, wenn Sie React seitdem verwenden Sie packen alles, was Sie zurückgeben, immer in div/div oder ähnliches, es sei denn, es ist sinnvoll, einen Container zu haben.

Ich bin mir ziemlich sicher, dass Sie für alle hier vorgestellten Anwendungsfälle <BunchOfComponents /> durch {getBunchOfComponents()} ersetzen könnten und die visuelle Ausgabe dieselbe wäre, ohne die praktischen und technischen Probleme im Zusammenhang mit Komponenten mit einzuführen Fragmente als Wurzel.

@syranide , aber jedes Mal, wenn sich eine der Komponenten ändert, müssen alle Geschwister neu berechnet werden ...

Auch wenn Sie einfaches Kaffeeskript verwenden, ist es einfach, ein Array zurückzugeben, also entkoppeln Sie bitte die Funktionalität von der jsx-Darstellung.
IOW Wenn es einfach ist, ein zurückgegebenes Array von Elementen zu handhaben, warten Sie nicht, bis jsx aufholt.

@syranide , aber jedes Mal, wenn sich eine der Komponenten ändert, müssen alle Geschwister neu berechnet werden ...

@wmertens Ja, aber oft hätten Sie das sowieso, weil das übergeordnete Element aus anderen Gründen neu rendern müsste oder einfach weil Sie die Daten sowieso über Requisiten erhalten. Aber ja, das ist der Unterschied, aber das bedeutet nicht, dass dieser Ansatz richtig ist, es ist eine Optimierung und es gibt viele Möglichkeiten, sie zu erreichen.

Auch wenn Sie einfaches Kaffeeskript verwenden, ist es einfach, ein Array zurückzugeben, also entkoppeln Sie bitte die Funktionalität von der jsx-Darstellung.

Das ist irrelevant und das ist kein Problem mit JSX. Ein großes Problem ist, dass Sie die technische, praktische und intuitive Annahme einer Komponente = ein Element/Knoten verlieren. Ich kann nicht für die Entwickler sprechen, aber ich würde das nicht freiwillig aufgeben, es ist eine sehr nützliche Annahme. Ich bin mir sicher, dass es gleich gute oder bessere Optimierungen gibt, die entwickelt werden könnten, wenn die Optimierung der einzige Grund ist, warum die Leute dies wollen.

@syranide Das größte Problem ist, dass Sie nicht immer eine Verpackung verwenden können
Element in HTML, wie in Tabellen, Listen, Flexbox, Kopf ... Umgehen
das führt zu hässlichem Code.

Ich wäre mit einem virtuellen Wrapper-Element, das nur rendert, vollkommen zufrieden
Kommentare, wie zuvor vorgeschlagen.

Am Freitag, 29. Mai 2015, 15:56 Uhr Andreas Svensson [email protected]
schrieb:

@syranide https://github.com/syranide aber jedes mal einer der
Komponentenänderungen alle seine Geschwister müssen neu berechnet werden ...

@wmertens https://github.com/wmertens Ja, aber oft würden Sie das tun
habe das sowieso, weil die Eltern für andere neu rendern müssten
Gründe, oder einfach, weil Sie die Daten sowieso über Requisiten erhalten. Aber
Ja, das ist der Unterschied, aber das bedeutet nicht, dass dieser Ansatz richtig ist,
Es ist eine Optimierung und es gibt viele Möglichkeiten, sie zu erreichen.

Auch wenn Sie einfaches Kaffeeskript verwenden, ist es einfach, ein Array zurückzugeben, also bitte
entkoppeln Sie die Funktionalität von der jsx-Darstellung.

Das ist irrelevant und das ist kein Problem mit JSX. Ein großes Problem ist das
Sie verlieren die technische, praktische und intuitive Annahme von _one
Komponente = ein Element/Knoten_. Ich kann nicht für die Entwickler sprechen, aber ich würde es nicht tun
Geben Sie das bereitwillig auf, es ist eine sehr nützliche Annahme. Ich bin sicher
Es gibt gleich gute oder bessere Optimierungen, die man entwerfen könnte, wenn
Optimierung ist der einzige Grund, warum die Leute dies wollen.


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an
https://github.com/facebook/react/issues/2127#issuecomment -106810565.

fwiw, Es ist relativ einfach , eine "Fragment"-Komponente in React zu hacken, die von React als ein Array ihrer Kinder behandelt wird. Schlüssel werden automatisch generiert, aber da dies nach der anfänglichen Validierung von Komponenten geschieht, wird nicht der übliche Fehler "keine Schlüssel angegeben" ausgegeben.

Abgesehen davon löst dieser Hack nur das, worüber @gaearon oben gesprochen hat - sich nicht mit hässlicher Array-Syntax / dem Festlegen willkürlicher Schlüssel in Ihrem JSX auseinandersetzen zu müssen - und nicht mit dem Problem, mehrere Knoten an der Wurzel der Rendermethode einer Komponente zurückzugeben.

Ich habe ein Problem mit der Idee, dass eine Komponente ein "Element/Knoten" zurückgeben muss. Für mich scheint es vollkommen vernünftig für eine JSX-Struktur von:

<Main>
  <Foo />
  <Fragment>
    <Bar />
    <Baz />
  </Fragment>
</Main>

um als DOM zu enden:

<div>
  <div>Foo</div>
  <div>Bar</div>
  <div>Baz</div>
</div>

Ich denke nicht, dass dies eine Verletzung des Prinzips der geringsten Überraschung ist, da Komponenten bereits alle möglichen "überraschenden Dinge" mit dem DOM tun, indem sie Lebenszyklus-Hooks verwenden (sehen Sie sich nur das übliche Wurmlochmuster an). Es ist allgemein anerkannt, dass eine Komponente nicht unbedingt dazu führt, dass ein einzelnes Element erstellt wird, und das ist in Ordnung, da einige Kompromisse eingegangen werden müssen, um mit dem DOM zu arbeiten.

Hier geht es auch nicht um "Optimierungen" oder auch nur darum, die Array-Syntax nicht zu mögen. Wie viele Benutzer bereits erwähnt haben, brechen _Wrapper-Elemente Stil und Layout auf ernsthafte Weise_. Tabellen sind am offensichtlichsten, aber Flexbox ist auch ein wichtiges Thema. Ich habe bereits CSS, das einfach Flex-Regeln auf Wrapper-Elemente anwendet, die nur wegen React existieren, und es ist ziemlich hässlich.

Für alle hier vorgestellten Anwendungsfälle bin ich mir ziemlich sicher, dass Sie ersetzen könnten mit {getBunchOfComponents()} und die visuelle Ausgabe wäre die gleiche, ohne die praktischen und technischen Probleme im Zusammenhang mit Komponenten mit Fragmenten als Root einzuführen.

Dies erfordert, dass Entwickler Kompromisse bei der Erstellung isolierter, wiederverwendbarer Komponenten eingehen – der Himmel steh ihnen bei, wenn sie sich entscheiden, ihre Reihe von Komponenten an anderer Stelle wiederzuverwenden – aufgrund eines zugrunde liegenden Implementierungsproblems in React. Ich denke nicht, dass das akzeptiert werden sollte.

@thomasboyt

EDIT: Mein Fehler, ich habe einige Ihrer Argumente mit der obigen Tabellendiskussion zusammengeführt, ich stimme weitgehend mit dem überein, was Sie sagen, denke ich. Aber es gibt immer noch Probleme mit Komponenten, die undurchsichtig sind, sodass das, was als nützliche transparente Hülle gedacht ist, für das übergeordnete Element undurchsichtig wird. Stellen Sie sich <Wrapper1><Wrapper2>...</Wrapper2></Wrapper1> vor, Wrapper1 kann die Kinder von Wrapper2 nicht sehen. Vielleicht ist wrapMyElements(...) einfach eine rundum bessere Lösung (einschließlich aller anderen notwendigen unterstützenden Funktionen).

Ich habe ein Problem mit der Idee, dass eine Komponente ein "Element/Knoten" zurückgeben muss. Für mich scheint es vollkommen vernünftig für eine JSX-Struktur von:

Komponenten sind mehr als nur dumme Verpackungen, sie haben einen Zweck. IMHO scheint es, dass die Rückgabe mehrerer Elemente einige sehr nützliche Erwartungen blockiert. Zum Beispiel wird React.render in Zukunft einen Begleiter bekommen, der ein Element rendert und die Knoten zurückgibt, dieser muss jetzt stattdessen ein Array von Knoten erzeugen.

Aber ich denke, ein sehr wichtiges Thema ist die Lesbarkeit, die meiner Meinung nach das größte Verkaufsargument von React ist, alles ist explizit.

<table>
  <tr>
    <td />
    <td />
    <td />
  </tr>
  <tr>
    <Columns1 />
    <Columns2 />
  </tr>
</table>

So gesehen macht es keinen Sinn, woher kommt die 3. Zelle? Vielleicht ist es tatsächlich falsch und es rendert 2 oder 4 Zellen, wer weiß, vielleicht ist es tatsächlich dynamisch und hängt von einer Stütze oder einem externen Zustand ab? Es gibt viele Variationen dieses Problems, die nur noch schlimmer werden, wenn Sie andere Nicht-HTMLDOM-Frontends berücksichtigen, die möglicherweise explizite Erwartungen haben. Eine andere zu berücksichtigende Sache ist, dass Elemente undurchsichtig sind. Wenn Sie also <tr /> durch <MyMagicalTr /> ersetzen, kann es nicht mit den einzelnen Zellen interagieren oder sogar ableiten, wie viele es gibt, also obwohl <MyMagicalTr /> akzeptiert möglicherweise nur <MyMagicalTd /> 's, es gibt keine Garantie, dass es tatsächlich mit ihnen interagieren kann.

Dies erfordert, dass Entwickler Kompromisse bei der Erstellung isolierter, wiederverwendbarer Komponenten eingehen – der Himmel steh ihnen bei, wenn sie sich entscheiden, ihre Reihe von Komponenten an anderer Stelle wiederzuverwenden – aufgrund eines zugrunde liegenden Implementierungsproblems in React. Ich denke nicht, dass das akzeptiert werden sollte.

"Dies erfordert, dass Entwickler Kompromisse beim Isolieren eingehen ...", aber das ist genau das Problem, wenn Sie mich fragen, wenn eine Komponente mehrere Elemente zurückgeben kann, ist sie nicht mehr isoliert, sie wird ersetzt, die Komponente tritt in die übergeordnete Komponente ein.

Hammer Nägel. Dass es sich dabei um ein zugrunde liegendes Implementierungsproblem handelt, ist eine andere Frage als die Frage, ob dies tatsächlich getan werden sollte oder nicht. Es ist nicht meine Entscheidung, aber ich sehe nicht, wie ein seltener Anwendungsfall ein überzeugendes Argument sein kann, ohne die damit verbundenen Kompromisse oder andere alternative Lösungen zu berücksichtigen.

IMHO sehe ich das Problem mit {getBunchOfComponents()} nicht, es ist explizit, es erlaubt uns, unsere nützlichen Erwartungen zu wahren. Wenn die Leistung ein Problem ist, dann React.createSmartFragment() (oder w/e) zur Rettung, ein transparenter Array/Objekt-ähnlicher Typ, der jedoch unabhängig von seinem übergeordneten Element aktualisiert werden kann.

Auch hier sind die React-Entwickler die Autorität (nicht ich), aber ich sehe hier kein überzeugendes Argument angesichts der verschiedenen Nebenwirkungen. Ich bin mir nicht einmal sicher, ob ich damit einverstanden bin, dass die vorgestellte Lösung überhaupt ein gutes Muster ist, selbst wenn sie unterstützt wird.

BEARBEITEN: Zur Verdeutlichung, vielleicht können Komponenten in Zukunft mehrere Elemente zurückgeben, da es andere offensichtlich vorteilhafte Anwendungsfälle gibt, insbesondere im Zusammenhang mit der Weitergabe von Kindern (wie dem, den Sie @thomasboyt zeigen), die Lesbarkeit bleibt erhalten.

Ich glaube, ich brauche noch ein bisschen Kaffee, bevor ich auf die philosophische Seite dieses Gesprächs eingehen kann (danke für die sehr guten Punkte, @syranide), aber auf der Seite der Implementierung habe ich gestern Abend angefangen, hier herumzustöbern, um zu sehen, wie möglich ist eine Änderung dieses Umfangs, die zu diesem Spike führt: https://github.com/facebook/react/compare/master...thomasboyt :fragment

Und hat hier eine kleine Demo rausgeschmissen: http://www.thomasboyt.com/react-fragment-demo/

Einige Beobachtungen zur Implementierungsseite der Dinge:

  • Es überrascht nicht, dass es sehr schwierig ist, ein System nachzurüsten, das "1 Komponente = 1 Knoten" erwartet, um mehr Knoten zu unterstützen ;)
  • Ich dachte ursprünglich, ich würde versuchen, Fragmente auf der Seite der DOM-Operationen zu verfolgen, damit die ReactMultiChild generierten Mutationsanweisungen gleich bleiben und Fragmente wie jeden anderen Knoten behandeln können. Ich konnte mir jedoch keine gute Möglichkeit vorstellen, den Status über die Anzahl der Knoten hinzuzufügen / welche Knoten Fragmente in die DOM-Statusverfolgung sind. So etwas wie das von @Prinzhorn erwähnte Kommentarfechten könnte funktionieren, aber ich bin vorsichtig bei allem, was eine DOM-Suche erfordern würde, wenn man die relativen Kosten berücksichtigt.
  • Nachdem ich diese Idee verworfen hatte, fügte ich allen Kindern einer ReactMultiChild -Komponente ein _nodeCount -Feld hinzu, damit es die Anzahl der tatsächlich in einem Fragment enthaltenen Root-Knoten nachverfolgen konnte.

Das Problem ist, dass dies bei einem anfänglichen Rendering einfach genug ist, indem nur die Kinder eines Fragments gezählt werden, das Aktualisieren der Knotenanzahl des Fragments bei nachfolgenden Mutationen scheint jedoch schwieriger zu sein. Dies ist auf meinem Zweig noch nicht geschehen (siehe https://github.com/thomasboyt/react/issues/2).

  • Viele DOM-Operationen verlassen sich auf den Zugriff auf den übergeordneten Knoten eines Elements, das anhand der internen Knoten-ID nachgeschlagen wird, um Elemente anzuhängen/zu verschieben/zu entfernen (siehe https://github.com/thomasboyt/react/issues/3). Da der updateComponent-Zyklus ReactMultiChild für die Weitergabe dieser ID verantwortlich ist, könnte er geändert werden, um eine Suche nach dem nächsten übergeordneten Knoten durchzuführen, der einen DOM-Knoten hat, aber das klingt teuer. Alternativ kann es möglich sein, eine interne Registrierung von Fragmentschlüsseln zu ihren "echten Knoten"-Schlüsseln zu haben.

Ich bin immer noch nicht davon überzeugt, dass es der beste Weg ist, von Fragmenten zu verlangen, dass sie ihre Stammknoten zählen (obwohl es mich zumindest zu dieser Demo gebracht hat), und das alles wurde ziemlich schnell und ziemlich spät in der Nacht zusammengehackt , also wenn noch jemand einen Vorschlag zur Umsetzung hat, gerne melden :>

@thomasboyt IIRC Das Hauptimplementierungshindernis kommt von React, das auf untergeordnete Knoten durch mountIndex verweist. Dies funktioniert nicht, wenn ein "Knoten" plötzlich zu einer beliebigen Anzahl von Knoten werden kann und dies möglicherweise ohne Aufrufen des übergeordneten Knotens geschieht, und es kann auch passieren mehrere Komponenten tief (Verpackung). Wenn ich mich nicht irre, ist es ziemlich trivial, dass React mehrere Root-Elemente unterstützt, solange sich die Anzahl nie ändert.

Ich denke also nicht, dass es besonders schwierig wäre, es einfach in React zum Laufen zu bringen, aber eine wirklich richtige Lösung ist problematischer und sollte wahrscheinlich das Löschen mountIndex beinhalten.

@syranide Richtig; Die Lösung, an der ich arbeite, führt tatsächlich ein neues nodeIndex ein, das der "echte Offset" eines Knotens sein soll (was mich daran erinnert, dass ich zurückgehen und mountIndex entfernen muss, da Ich denke, es ist jetzt in meiner Filiale unbenutzt).

Aber wie Sie anmerken, ist dies problematisch, wenn sich die Anzahl der Stammelemente ändert, da die nodeIndex einer Komponente aktualisiert werden müssen, wenn sich die Anzahl der Knoten einer vorherigen gleichgeordneten Komponente ändert. Dafür muss noch eine Lösung gefunden werden.

Ich bin auch auf Flexbox-Probleme gestoßen. @syranide könnten Sie bitte etwas mehr auf Ihre vorgeschlagene Lösung "getBunchOfComponents" eingehen? Als React-Neuling ist es schwierig, eine Vorstellung davon zu bekommen, wo man diese Funktion definiert / wie man sie anwendet.

@landabaso

function getBunchOfComponents(...) {
  return [<ColumnA key="a" />, <ColumnB key="b" />];
}

Hey,

Ich habe nicht den ganzen Thread gelesen, aber hier ist ein Renderoptimierungs-Anwendungsfall, der diese Funktion möglicherweise erfordert:

http://stackoverflow.com/questions/30976722/react-performance-rendering-big-list-with-purerendermixin

Wenn diese Funktion veröffentlicht wird, benötigt ReactCSSTransitionGroup keinen Wrapper -Knoten mehr, richtig?

@slorber Ja, das stimmt wahrscheinlich.

Laufen Sie in die Notwendigkeit für diese Funktion jeden Tag.

Wenn Sie viele kleine Komponenten haben (dh sehr modular entwerfen), müssen Sie am Ende alle möglichen Dinge in divs einpacken, die nicht sein sollten. Ich könnte mich vermischen, aber ich denke, das bezieht sich auf dieses Problem.

Für <div> 's können Sie sie in <div> , aber für Tabellenzeilen <tr> Elemente ist es nicht so einfach. Sie können <tr> in <tbody> $ einwickeln, aber es ist möglicherweise nicht wünschenswert, mehrere Schichten von <tbody> <tr> .

Das Szenario, das ich genannt habe, war der Versuch, eine Komponente zu haben, die <link> - und <script> -Elemente bereitstellt, ohne vollständig der <head> -Renderer werden zu müssen.

Ich habe oben in dieser Ausgabe eine Anmerkung hinzugefügt. Bitte lesen Sie es, bevor Sie kommentieren. https://github.com/facebook/react/issues/2127#issue -41668009

Bump ... Ich habe einen großen Bedarf dafür auf der Serverseite. Aufgrund des Abschnitts <head> ist es sehr kompliziert, vollständige Webseiten (mit Ausnahme von doctype) ohne die Möglichkeit, Fragmente zu rendern, zu rendern. Ich arbeite derzeit mit Mixins und ein wenig Logik im endgültigen Rendering daran herum, aber es wäre viel einfacher, wenn das Rendern mehrerer Komponenten unterstützt würde.

@impinball Sie können versuchen, etwas Ähnliches wie „ react-document-title “ zu schreiben, basierend auf „ react-side-effect “, um diese Probleme zu lösen. Ich konnte dasselbe für Meta-Tags, Header, Titel und gelegentlich Weiterleitungen tun

Ich habe dieses Problem auch, gibt es vorerst irgendwelche Workarounds? Ich konnte {getBunchOfComponents()} nicht wie vorgeschlagen zum Laufen bringen.

Keine anderen als die bereits erwähnten.

@jonchay Sie könnten eine Komponente erstellen, die nur ihre untergeordneten Elemente rendert.

function statelessWrapper(props) {
   return props.children;
}

und dann um es zu benutzen:

render() {
   return (  
      <statelessWrapper>
         {renderABunchOfComponents()}
      </statelessWrapper>
    );
}

@whatknight Das funktioniert nicht, außer in Fällen, in denen return renderABunchOfComponents(); bereits funktioniert.

  render () {
    let user = this.state.user
    let profile = user.get('data')
    let view = null

    if (user.get('status') === 'fetched') {
      view = (
        <h1>{profile.get('login')}</h1>
        <img src={profile.get('avatar_url')} />
        <dl>
          <dt>email</dt>
          <dd>{profile.get('email')}</dd>
        </dl>
      )
    } else if (user.get('status') === 'fetching') {
      view = <h1>fetching</h1>
    } else if (user.get('status') === 'error') {
      view = <h1>{profile.message}</h1>
    }

    return (
      <div className={className}>
        {view}
      </div>
    )
  }

Es sollte zumindest eine Möglichkeit geben, mehrere Fragmente während der Interpolation und "Assemblierung" zurückzugeben. Das obige Beispiel beschwert sich darüber, dass img und h1 nebeneinander liegen, aber sie werden sich sowieso im Haupt-Wrapper befinden. Das ist ein Wrapper-Element, das ich gerne loswerden könnte.

@kilianc in diesem Fall kannst du einfach schreiben

      view = [
        <h1 key={0}>{profile.get('login')}</h1>,
        <img key={1} src={profile.get('avatar_url')} />,
        <dl key={2}>
          <dt>email</dt>
          <dd>{profile.get('email')}</dd>
        </dl>,
      ]

So wie Sie es verwenden, macht es keinen Unterschied, ob dieses Problem behoben wird.

Ich brauche diese Funktion aus bereits genannten Gründen, also habe ich versucht, einen <frag></frag> -Container unter https://github.com/mwiencek/react/tree/frag-component zu implementieren

Die Implementierung ist nicht wirklich hübsch, aber wenn es für die Leute funktioniert, kann ich eine PR einreichen und die React-Entwickler es auseinander reißen lassen.

@mwiencek Sieht so aus, als ob Ihre Implementierung nicht funktioniert, wenn sich die Anzahl der untergeordneten Elemente in einem Fragment in einem Update ändert (_nestedChildCount wird nur in mountComponent festgelegt)? Es ist ein wenig knifflig, damit das alles gut funktioniert. Sieht aber so aus, als hättest du einen guten Start hingelegt. Ich habe tatsächlich vor kurzem wieder darüber nachgedacht und vielleicht habe ich einen robusten Weg gefunden, dies zu erreichen. Ich melde mich wieder, wenn ich Erfolg habe.

@spicyj ja , du hast recht, das muss ich mir mal anschauen...

Super begeistert, dass wir vielleicht bald eine richtige Implementierung sehen werden. :) Fühlen Sie sich frei, Tests aus diesem Zweig zu kopieren, wenn sie überhaupt von Nutzen sind.

@spicyj Ist es nicht der richtige Weg, createFragment zu verwenden und JSX in das umwandeln zu lassen? Oder wollen wir wirklich, dass Fragmente Elemente sind?

Um den letzten Kommentar von @syranide aufzubauen und zu erweitern, scheint es keine Notwendigkeit für eine zusätzliche "Fragment-API" zu geben, wenn render Arrays als Rückgabewert zulässt. JSX könnte mehrere Root-Elemente in ein Array umwandeln, was auch für Rückgabewerte jeder anderen Funktion funktionieren würde. Anstatt also eine zusätzliche API-Oberfläche einzuführen, die Dokumentation und Lernen erfordert, könnte eine der Einschränkungen von React einfach entfernt werden.

Dies würde zumindest babel-plugin-transform-react-jsx (Implementierung) und auch babel-plugin-syntax-jsx (Beseitigung des Analysefehlers für benachbarte Wurzelelemente) betreffen. Während das Ändern des ersteren ziemlich sicher zu sein scheint, kenne ich den Umfang / die Verwendung des letzteren und die Auswirkungen der vorgeschlagenen Änderung auf andere Projekte nicht.

Damit ist der Anwendungsfall einer Bedingung mit mehreren Elementen noch nicht abgedeckt. Ich halte "Verwenden Sie ein Array und fügen Sie jedem Element manuell ein beliebiges key={...} hinzu" nicht für eine angemessene langfristige Lösung.

stimme @dantman zu

Jup, guter Punkt. Die automatische Schlüsselgenerierung sollte über die Transformation eingebaut werden. Die Verwendung des Array-Index als Schlüssel sollte ausreichen, da sich die Elemente nicht ändern.

Bedingungen können auch in die Transformation integriert werden, oder Sie können alternativ JSX-Control-Statements verwenden. Habe es dort so umgesetzt, daher die Idee.

Um Updates korrekt zu handhaben, dachte ich, dass die Lösung, die @spicyj für #5753 gedacht hat, auch für Fragmente funktionieren könnte (den Inhalt in so etwas wie <!-- react-frag: 1 --><!-- /react-frag: 1 --> einpacken). Ja, die Kommentare sind ein bisschen hässlich, aber es ist viel zuverlässiger als das, was ich mit _nestedChildCount machen wollte. Dieser Ansatz wird jetzt unter https://github.com/mwiencek/react/tree/frag-component verwendet

Ich habe das bisher nicht im Thread erwähnt gesehen, aber ich denke, das Lösen dieses Problems verbessert auch die Zusammensetzbarkeit. Stellen Sie sich zum Beispiel vor, Sie haben ein Raster, in dem die Zellen in einer bestimmten Reihenfolge ausgeblendet werden sollen. Idealerweise sind hier zwei Komponenten im Spiel: eine für das Layout und eine für die Animation. Sie hätten eine API wie diese:

<GridLayout
  columns = { 3 }
>
  <FadeAnimator
    springConfig = { springConfig }
  >
    { ...cells }
  </FadeAnimator>
</GridLayout>

Dies würde es Ihnen ermöglichen, zu einem anderen Layout oder einer anderen Animation zu wechseln, ohne dass der eine die Implementierungsdetails des anderen kennen muss. GridLayout würde erwarten, eine Liste der Kinder zu erhalten. FadeAnimator würde diese Liste abfangen, die entsprechenden Stile und/oder Ereignis-Listener einfügen und die neue Liste für GridLayout zum Konsumieren zurückgeben. Es gibt keinen Grund für FadeAnimator , sich Gedanken über das Layout eines Grids zu machen, außer dass React-Elemente keine Arrays vom Rendern zurückgeben können. Darüber hinaus gibt es keine einfache Möglichkeit, das Gitter beispielsweise durch ein gemauertes Layout zu ersetzen, da FadeAnimator als Container für seine untergeordneten Elemente fungieren soll.

Mit den aktuellen Einschränkungen könnten Sie Folgendes tun:

<FadeAnimator
  wrapper = {
    <GridLayout
      columns = { 3 }
    />
  }
  springConfig = { springConfig }
>
  { ...cells }
</FadeAnimator>

// FadeAnimator
render() {
  return React.cloneElement(
    props.wrapper,
    null,
    props.children
  );
}

aber das macht den Code weniger klar, komplexer und schwerer zu erstellen.

Fragment-API hinzufügen, um die Rückgabe mehrerer Komponenten vom Rendern zu ermöglichen!
Fragment-API hinzufügen, um die Rückgabe mehrerer Komponenten vom Rendern zu ermöglichen!
Fragment-API hinzufügen, um die Rückgabe mehrerer Komponenten vom Rendern zu ermöglichen!
Fragment-API hinzufügen, um die Rückgabe mehrerer Komponenten vom Rendern zu ermöglichen!
Fragment-API hinzufügen, um die Rückgabe mehrerer Komponenten vom Rendern zu ermöglichen!
Fragment-API hinzufügen, um die Rückgabe mehrerer Komponenten vom Rendern zu ermöglichen!
Fragment-API hinzufügen, um die Rückgabe mehrerer Komponenten vom Rendern zu ermöglichen!
Fragment-API hinzufügen, um die Rückgabe mehrerer Komponenten vom Rendern zu ermöglichen!

@texttechne Vorschlag ist besser. Anstatt eine zusätzliche API einzuführen, sollte React mehrere Root-Elemente beim Rendern verarbeiten.

Der Umgang mit mehreren Root-Elementen beim Rendern wäre meiner Meinung nach schwierig.
Es bedeutet dort: https://github.com/facebook/react/blob/master/src/renderers/shared/reconciler/ReactCompositeComponent.js#L1089

Sie hätten eher ein Array von Elementen als ein Element.
Aus diesem Grund müssten Sie, soweit ich es verstehe, jetzt mehrere React-Elemente instanziieren: https://github.com/facebook/react/blob/master/src/renderers/shared/reconciler/ReactCompositeComponent.js# L471

Mounten Sie dann mehrere instanziierte React-Elemente: https://github.com/facebook/react/blob/master/src/renderers/shared/reconciler/ReactCompositeComponent.js#L471

Und stimmen Sie alle Markups ab, die in der guten Reihenfolge produziert wurden.

Ich denke, es bringt Nachteile mit sich, die den Versöhnungsprozess vielleicht nicht umgehen wollen.
Wollen wir Fragmente als Elemente oder Fragmente als Zuckersyntax um Transformationen haben?

Ich denke, dass Fragment als Element in Ordnung ist, wir müssten nur einen neuen Typ von internen Knoten erstellen, ähnlich wie Textknoten oder leere Knoten, richtig? Obwohl ich nicht weiß, wie wir sie handhaben würden.

Wie gehen Sie beispielsweise damit um, wenn einer der Roots ausgehängt ist? Wie gehen Sie mit Updates richtig um?
Oder wie verwalten Sie mehrere Roots innerhalb der DevTools? (offensichtliche Antwort: Reparieren Sie die DevTools ...)

Ich denke, dass ein Fragment eine zusammengesetzte Komponente ist. Wo genau ist der Unterschied?
Wenn wir am Ende Code duplizieren, um Fragmente zu implementieren, sollten wir besser die Sugar-Syntax implementieren, um die React-Interna "unberührt" zu halten.

Ich frage mich, ich habe mit React-Interna rund um die Subtree-Frage herumgespielt (renderSubtreeIntoContainer) und ich habe das Gefühl, dass es etwas verwandt ist. Wenn Sie in einen neuen Teilbaum rendern möchten, müssen Sie tatsächlich eine neue Wurzel rendern. Wenn wir also mehrere Wurzeln auf Baumebene unterstützen, rendern wir jedes Mal neue Wurzeln:

<p>Hi</p>
<p>There</p>

würde zu zwei "render into a new root"-Aufruf führen.

Anstatt eines Aufrufs, wenn wir einen Wrapper verwenden, richtig? Was ist mit der Leistung? Einfachheit? Um ehrlich zu sein, mein Gefühl ist: Wir sollten React-Interna nicht anfassen, um mit dieser Situation umzugehen. Können wir dieses Kunststück vielmehr mit JSX vollbringen? Können wir die JSX-Syntax verbessern?

(_Haftungsausschluss_: Ich bin nicht vollständig an React-Interna gewöhnt, und es könnte einige Teile geben, die ich nicht vollständig verstehe oder die ich nicht verstanden habe. Ich entschuldige mich für das Missverständnis.)

Edit: Dinge reparieren/klären. Außerdem formatiert GitHub E-Mails auf mysteriöse Weise seltsam, also musste ich den Codeblock neu formatieren ... :-(

Hallo, zentraler Mithril-Mitwirkender/Committer hier.

TL;DR: Fragmente sind extrem hart, selbst wenn die API und die Interna es sind
einfach.

Übrigens weiß ich aus Erfahrung, dass es _sehr_ schwierig umzusetzen ist. Dies
wurde auch mehrfach für Mithril angefordert, aber wegen abgelehnt
die schiere Schwierigkeit. Jeder Versuch, es zu implementieren, ist mit at gescheitert
mindestens ein Drittel der Testsuite schlägt fehl.

Ich arbeite immer noch an Details einer vdom-Bibliothek, die ich schreiben möchte,
und es wird alles als Fragment behandeln, aber das ist etwas, was Sie haben
um den Rendering-Teil buchstäblich von Grund auf neu zu schreiben. Wie reagieren,
Es wird vom DOM entkoppelt, aber die API wird sich erheblich unterscheiden
konzeptionell zum Rendern.

Hier ist der Haken an Fragmenten: Sie müssen sie vollständig verwalten
intern oder Sie unterscheiden sie nicht richtig. Eben
document.createContextualFragment ist nutzlos. Nur als Beispiel, lassen Sie uns
Transformiere zwei Bäume, Rendering weggelassen:

// Before
A {}
fragment {
  B[class="foo"] {}
  B[class="bar"] {}
}
C {}
D {}

// After
A {}
B[class="foo"] {}
fragment {
  C {}
}
D {}

Die richtige Transformation dafür sollte darin bestehen, sowohl die B -Elemente als auch das C -Element zu ersetzen und den Rest unberührt zu lassen. Das herauszufinden ist nicht trivial, und Sie müssen die untergeordneten Elemente des Fragments im Grunde iterieren, während Sie die Tatsache ignorieren, dass sie sich in einem Fragment befinden.

Aber wenn das Fragment weg ist, müssen Sie mit der Hook-Semantik umgehen, wie z
shouldComponentUpdate (Ich erinnere mich nicht an den Namen von React für diesen Hook). Damit
Sie müssen die Fragmente immer noch unabhängig verfolgen. Sie unterscheiden ihre
Inhalte, als ob sie Teil ihres übergeordneten Fragments wären, aber Sie haben es immer noch
um die Position dieses Fragments für die Komponente zu verfolgen.

Oder anders gesagt, Komponenten sind nicht mehr untrennbar mit ihnen verbunden
DOM-Knoten. Stattdessen werden sie mit dem entsprechenden Fragment verknüpft. Wie die meisten anderen vdom-Bibliotheken und -Frameworks koppelt React die Komponente selbst mit den erwarteten Typen an ihre Baumdarstellung. Dies ist der einfachste Weg, einen Diff-Algorithmus zu implementieren
behandelt Komponenten. Wenn sie entkoppelt sind, müssen Sie sie trennen
Buchhaltung für beide. Sie initialisieren keine Komponenten, wenn Sie initialisieren
der Knoten. Es sind jetzt zwei völlig getrennte Prozesse. Es ist schwer zu tun
anfangs, und es ist noch schwieriger, danach Unterstützung hinzuzufügen.

Danke allen für die Worte. Wir wissen, dass dies schwierig ist und haben es immer noch auf unserer To-do-Liste. (Begeistert zu fragen wird es nicht früher schaffen @janryWang.)

@isiahmeadows FYI, Mithrils Rewrite-Zweig unterstützt Fragmente.

@spicyj Sie können sich gerne die Implementierung [1] [2] und die Tests [1] [2] ansehen, falls Sie sie nicht bereits verfolgen. Die ganze Diff-Engine hat nur etwa 400 LOC, also sollte es hoffentlich einfach zu folgen sein

@isiahmeadows Ich denke, GitHub hat einen Teil Ihres Kommentars gefressen. Der Codeblock ist defekt und ich kann die erste Instanz von <D /> nicht sehen.

In E-Mail sieht es aber OK aus. Vielleicht haben Sie einen Fehler in GitHub gefunden?

Leider verhält sich das Markdown-Handling von GitHub anders, wenn ein Kommentar aus einer E-Mail stammt. Ich habe den Kommentar bearbeitet, um eine Leerzeile zu entfernen, und jetzt wird er angezeigt.

Ich habe die ursprüngliche E-Mail an support@github weitergeleitet. Hoffentlich können sie den Parser reparieren. 😃

@lhorie Sie verwenden Array-Syntax für fragment ?
Haben Sie Polyfill für DocumentFragment?

Und die Verwendung eines "Pseudo"-Wrapper-Elements wie eines HTML-Kommentars ist keine Option? Ich dachte, auf diese Weise wurden Textknoten "gelöst" ...

Danke für die Korrektur dieses Kommentars @spicyj

Um die Bedenken anzusprechen, die @isiahmeadows in seinem Beispiel geäußert hat: Die neue Mithril-Engine folgt aus mehreren Gründen _nicht_ der von @isiahmeadows vorgeschlagenen Semantik:

  • Die Implementierung dieser Semantik würde die Unterscheidung _erheblich_ komplexer machen
  • es würde es schwierig machen, über Schlüssel und schlüsselbezogene Fehler nachzudenken, da es möglich wird, dass Schlüsselräume aus Komponenten und sogar in gleichgeordnete und untergeordnete Komponenten übergehen.
  • es würde Fragment-Lebenszyklen nicht intuitiv machen (z. B. wird in diesem Beispiel B.bar entfernt, aber auch das Fragment, und ein neues Fragment wird erstellt, um C zu umhüllen). Dies verstößt gegen das allgemeine Prinzip, dass Lebenszyklen "kaskadieren", was bedeutet, dass Sie nicht mehr sicher sein können, dass ein untergeordneter Knoten entfernt wird, wenn ein bestimmter übergeordneter Knoten entfernt wird. Wie beim vorherigen Punkt kann dies zu Undichtigkeiten bei den Verkapselungsfähigkeiten einer Komponente führen.
  • Wenn man hypothetisch auf Diff-Probleme im Zusammenhang mit einer Diff-Engine stößt, die sich nicht an diese Semantik hält, ist die Lösung im Anwendungsbereich so trivial wie das Einwickeln eines Fragments um den störenden Knoten.

Es würde mich interessieren, ob das Kernteam die Anmerkung oben in Bezug auf Folgendes erweitern könnte: _warum_ dies mit der aktuellen Architektur schwierig ist. Angesichts der Tatsache, dass die Rendering-Engine von React und Mithril im Grunde versucht, die gleichen Probleme zu lösen, und dass Mithril jetzt Fragmente in einem Maße unterstützt, das ich für machbar und nützlich halte, ist die Implementierung in React möglicherweise machbarer, wenn verschiedene Aspekte der Semantik berücksichtigt werden werden separat bewertet (und möglicherweise abgelehnt), wie es bei Mithril der Fall war.

Beachten Sie, dass ich meinen Kommentar korrigiert habe. Ich habe ein paar Fehler gemacht, und GitHub ist nicht gut darin, E-Mail-Antworten zu gestalten ... :Stirnrunzeln:

@Primajin Das habe ich mich auch gefragt, aber ich vermute, sie würden als ein Element weitergegeben. Es ist wichtig, Fragmente zusammensetzbar zu machen (siehe mein Beispiel oben ). Es gibt jedoch wahrscheinlich Zeiten, in denen Sie sie auch als eine Einheit behandeln möchten.

Vielleicht sollte React.Children.map Fragmente erweitern. Wenn Sie über jedes Kind (einschließlich Kinder von Kindfragmenten) iterieren möchten, verwenden Sie Children.map . Wenn Sie Fragmente als undurchsichtige Box behandeln möchten, arbeiten Sie direkt mit props.children als {Array, Element}.

@lhorie Ich war jedoch nicht so an der Neufassung beteiligt, daher bin ich mit seinen Feinheiten nicht so vertraut. Ich war damit beschäftigt, dass ich diese Woche ein und nächste Woche drei Abschlussprüfungen habe, außerdem arbeite ich mit jemandem zusammen, um ein Praktikum zu organisieren, das mein College benötigt. Ich habe mich auch darauf konzentriert, Techtonic fertigzustellen, was ich _fast_ mit der CLI erledigt habe (ein Test ist kaputt, der nicht sein sollte).

@isiahmeadows Nur eine freundliche Erinnerung, um beim Thema zu bleiben. Nutzen Sie gerne den Mithril-Gitter-Raum, wenn Sie sich über andere Themen austauschen möchten.

@appsforartists

Vielleicht sollte React.Children.map Fragmente erweitern

Mithril Stable macht intern etwas Ähnliches (dh Sub-Arrays abflachen), aber ich entferne mich aus Leistungsgründen von diesem Modell (und auch aufgrund einiger historischer Kopfschmerzen in Bezug auf Vnode-Listen, die geschlüsselte und nicht geschlüsselte Knoten gemischt haben). Wäre vielleicht etwas zu überlegen.

Und die Verwendung eines "Pseudo"-Wrapper-Elements wie eines HTML-Kommentars ist keine Option? Ich dachte, auf diese Weise wurden Textknoten "gelöst" ...

Wir verwenden https://github.com/mwiencek/react-packages seit einigen Monaten in der Produktion. Es verwendet diesen Kommentar-Wrapper-Ansatz, sodass Fragmente eindeutig verschachtelt werden können.

@mwiencek Ist es möglich, Ihren Ansatz ohne benutzerdefiniertes Reaktionspaket zu verwenden?

@mwiencek sind die Kommentar-Wrapper überhaupt notwendig? Ich würde von Fragmenten keine cleveren Dinge erwarten, wenn Sie ein Element aus einem Fragment in ein Geschwisterfragment oder das Wurzelelement verschieben, kann es einfach neu erstellt werden.

Wenn Sie also dem vdom-Baum der Reihe nach folgen, brauchen Sie keine Kommentare, oder doch?

Wie auch immer, Ihre Lösung sieht auf den ersten Blick so aus, als wäre sie genau das, was zur Lösung dieses Problems benötigt wird. 👍

Nicht unbedingt, aber sie haben die Implementierung in diesem Fall vereinfacht.

Es ist also im Grunde derzeit nicht möglich, mit React richtige Beschreibungslisten <dl> zu erstellen?

<dl>
  <dt>Def 1</dt>
  <dd>Some description</dd>
  <dt>Def 2</dt>
  <dd>Some other description</dd>
</dl>

@KaiStapel Bei diesem Problem geht es darum, mehrere Komponenten (oder Elemente, denke ich) von render() zurückzugeben. Solange Ihre render -Funktion nur ein Root-Element / eine Root-Komponente zurückgibt, sollte sie funktionieren.

OK:

render() {
  return (
    <dl>
      <dt>Def 1</dt>
      <dd>Some description</dd>
      <dt>Def 2</dt>
      <dd>Some other description</dd>
    </dl>
  )
}

Nicht ok:

render() {
  return (
    <h2>my list</h2>
    <dl>
      <dt>Def 1</dt>
      <dd>Some description</dd>
      <dt>Def 2</dt>
      <dd>Some other description</dd>
    </dl>
  )
}

@GGAlanSmitee Gut fest codiert ja, aber du kannst nicht:

<dl>
   loop here and print out dt/dd pairs
</dl>

Was sehr traurig ist. Das Gleiche gilt auch für Tabellen mit Zeilenspannen, da Sie nicht zwei <tr> Elemente gleichzeitig rendern können :(

Von oben:

"Me too" und "+1" sind nicht wertvoll, ebensowenig Anwendungsfälle, die bereits in den Kommentaren geschrieben wurden (z. B. wissen wir, dass Sie <tr>- oder <dd>-Elemente nicht mit einem <div> setzen können). .

Angesichts der Tatsache, dass es eine funktionierende Lösung in https://github.com/mwiencek/react-packages gibt, besteht eine Chance, dass dies bald Teil von React ist? Oder warten wir auf den neuen Versöhner?

Vorausgesetzt, es gibt eine funktionierende Lösung in https://github.com/mwiencek/react-packages

Setzen Sie es erfolgreich in realen Projekten ein?

@mwiencek

Die Implementierung ist nicht wirklich hübsch, aber wenn es für die Leute funktioniert, kann ich eine PR einreichen und die React-Entwickler es auseinander reißen lassen.

Klar, bitte PN schicken!

Was das Einreichen einer PR betrifft, das letzte, was ich von @spicyj gehört habe, war, dass sie den neuen Kernalgorithmus fertigstellen und damit eine richtige Lösung finden wollten, da die Kommentarknoten in React Native nicht wirklich Sinn machen. Ich habe den Status nicht verfolgt, aber ich glaube nicht, dass sich diese Pläne geändert haben. Ich bin froh, dass die Leute die Pakete in der Zwischenzeit nützlich finden.

Der neue Algorithmus ist in Arbeit und unterstützt Fragmente. Ich würde jedoch nicht erwarten, dass es in den kommenden Monaten produktionsreif wird. Ich frage mich, ob es zu schade ist, dies zuerst zu React DOM und später zu React Native hinzuzufügen? Der Nachteil ist, dass es das Ökosystem ein wenig fragmentiert (Wortspiel beabsichtigt!), aber es kann uns etwas Zeit geben, mit dieser Funktion zu experimentieren. Wir haben heute ein Teammeeting, also werde ich diese Frage stellen, wenn wir Zeit haben, um ein besseres Verständnis zu bekommen.

@gaearon Kann ich nur darauf hinweisen, dass die Unterstützung von Fragmenten super einfach ist, es ist nur Zucker, ich verwende derzeit selbst <frag> als winzigen trivialen Wrapper. Ist die Rückgabe mehrerer untergeordneter Elemente als Komponentenstamm wirklich so wichtig?

@syranide Ich verwende den benutzerdefinierten Build mit Frag in der Beta-Umgebung, möchte jedoch stattdessen den offiziellen React-Build verwenden. Können Sie Ihren <frag> -Wrapper bereitstellen? :) Danke

@amertak

import React from 'react';
import createFragment from 'react-addons-create-fragment';

let nativeCreateElement = React.createElement;

React.createElement = function() {
  if (arguments[0] !== 'frag') {
    return nativeCreateElement.apply(this, arguments);
  }

  let length = arguments.length;
  if (length <= 2) {
    return null;
  }

  let children = {};
  for (let i = 2; i < length; i++) {
    children['~' + (i - 2)] = arguments[i];
  }

  return createFragment(children);
};

Darüber haben wir im letzten Teammeeting ausführlicher gesprochen. Der Konsens ist, dass wir nicht mit dieser speziellen Implementierung gehen wollen. Diese Funktion wird jedoch in der langfristigen Neufassung des Kerns unterstützt (vorerst kein Zeitplan dafür).

Wir werden es auch wieder als eines der Dinge betrachten, an denen wir möglicherweise in der zweiten Hälfte dieses Jahres arbeiten könnten, falls die Neufassung zu lange dauert oder nicht funktioniert. Keine Garantie, dass es auf die Liste kommt, aber wir werden Sie alle auf dem Laufenden halten, wenn es auftaucht.

Um eine bessere Vorstellung davon zu bekommen, woran wir arbeiten, sehen Sie sich bitte unser Meeting-Notizen-Repository an! Unsere neueste Diskussion dazu finden Sie unter https://github.com/reactjs/core-notes/blob/master/2016-07/july-07.md.

@gaearon Es wäre interessant, zumindest eine offizielle Frag-Syntax zu haben.

@syranide Vielen Dank für den Code, aber leider scheint ich ihn nicht verwenden zu können, da ich die frag als Root-App-Komponente benötige, die von der ReactDOM.render -Methode gerendert wird, und diese Methode akzeptiert kein Fragment .

Trotzdem danke, es wird für andere Leute nützlich sein, die frag nicht als App-Root benötigen.

@amertak Ja, es dient nur dazu, eine vernünftigere Syntax zum Erstellen von Fragmenten zu aktivieren, es fügt keine neuen Funktionen hinzu.

@syranid
Ich dachte, ob es möglich wäre, Kommentare manuell zu rendern und als weitere Komponente zu behandeln (das ist möglicherweise nicht erforderlich)?
Intern werden Kommentare als #comment -Typ gehandhabt, sodass sie möglicherweise angerufen werden können
React.createComponent('#comment', { ... }, children) ?
Nur eine Idee. Kleine Problemumgehung.

Das Wichtigste, was hier fehlt, ist die Möglichkeit, den comment -Knoten zu rendern, habe ich recht? :)

@gaearon Ein bisschen traurig, dass das nicht bald kommt, aber ich schätze die Transparenz. Gut aufschreiben!

Eine alternative Lösung bis zu einem Update ?
Für mich muss ich ein Dropdown-Menü von Botstraap rendern

render(){
    return (
        <ButtonNotification/>
        <ul className="dropdown-menu">
            {this.state.items.map(this.addItem)}
        </ul>
    );
}
ReactDOM.render(
    React.createElement(NotificationHandler, null),
    document.getElementById("listNotification")
);

Aber ist nicht möglich, eine idee ?
Danke,

http://getbootstrap.com/components/#btn -dropdowns-single

Es ist eindeutig in ein einzelnes <div class="btn-group"> verpackt, wie in den Dokumenten gezeigt

Ja natürlich, aber es gibt zwei Elemente, die in <div class="btn-group"> sind.

render(){
    return (
        <ButtonNotification/> //ELEMENT 1
        <ul className="dropdown-menu"> //ELEMENT 2
            {this.state.items.map(this.addItem)}
        </ul>
    );
}
ReactDOM.render(
    React.createElement(NotificationHandler, null),
    document.getElementById("listNotification") //is DIV#listNotification
);
<div id="listNotification" class="btn-group"><!--wrap-->
    <a href="#">button notification</a> <!--ELEMENT1-->
    <ul> <!--ELEMENT2-->
        <li></li>
        <li></li>
    </ul>
</div>

Und zwei Elemente, die in ein einzelnes Element gewickelt sind, sind nicht möglich.
Danke für deine Zeit @Primajin

Einfach alles um eine Ebene verschieben:

render(){
    return (
        <div className="btn-group"> //WRAP
            <ButtonNotification/> //ELEMENT 1
            <ul className="dropdown-menu"> //ELEMENT 2
                {this.state.items.map(this.addItem)}
            </ul>
        </div>
    );
}
ReactDOM.render(
    React.createElement(NotificationHandler, null),
    document.getElementById("listWrapper") //or whatever your list is called
);

Okay, aber ich habe andere Elemente im übergeordneten Element.
Dadurch wird das Problem nur verschoben.

<div ...> <--!listWrapper-->
    <div class="btn-group">....</>
    <div class="btn-group">....</>
    <--!React-->
    <div class="btn-group"> //WRAP
        <ButtonNotification/> //ELEMENT 1
        <ul className="dropdown-menu"> //ELEMENT 2
            {this.state.items.map(this.addItem)}
        </ul>
    </div>
    <--!React-->
    <div class="btn-group">....</>
</div>

Und in diesem Fall ersetzt React alle enthaltenen.
Ist es möglich, ein "Hinzufügen" durchzuführen, ohne die anderen Elemente zu ersetzen?

Danke,

@ rifton007 so funktioniert es nicht. Sie können mehrere Elemente/Komponenten als Geschwister haben, die in einem Container verpackt sind. Die Einschränkung besteht darin, dass eine Komponente nicht mehrere return Elemente enthalten kann. Der Code, den du gerade gepostet hast, wird funktionieren.

Davon abgesehen, wenn Sie ein Beispiel finden, das nicht funktioniert, ist es höflich, den gesamten Thread zu lesen und zu überlegen, ob Sie ein _neues_ Beispiel hinzufügen oder nur dasselbe Problem wiederholen, das bereits anerkannt wurde. Dies ist eine bekannte Einschränkung, und dieser Thread enthält eine ausführliche Diskussion der Details und Gründe für die Einschränkung. Dan hat auch erklärt, dass sie beabsichtigen, dies letztendlich zu beheben. Was versuchen Sie zu erreichen, indem Sie auf ein anderes Beispiel für ein anerkanntes Problem hinweisen?

Entschuldigung, ich wollte nur wissen, ob jemand in der Zwischenzeit eine alternative Lösung hat.
Sie können meine Beiträge bei Bedarf löschen.

Ich erstelle eine App mit Framework7 und React, das Framework7-HTML-Format ist jedoch behoben.

<div class="page"><div class="navbar"></div><div class="searchbar"></div><div class="page-content"></div><div class="toolbar"></div></div>

Ich kann die untergeordneten Elemente der ersten Ebene (Navigationsleiste, Suchleiste) nicht in andere Div-Elemente einschließen, die keine „Seiten“-Klasse haben

Ich habe eine Komponente, die eine Liste von Zeilen zurückgibt

in einer Tabelle verwendet werden, und ich kann sie nicht in ein zusätzliches HTML-Tag einschließen (nicht vom HTML5-Standard erlaubt - ich kenne tbody, aber ich habe möglicherweise mehrere Zeilen, die von mehreren untergeordneten Komponenten zurückgegeben werden, die möglicherweise zu einem einzigen tbody kombiniert werden müssen ). Wurde die von @Prinzhorn erwähnte Technik – diese Kinder in einen HTML-Kommentar zu verpacken – tatsächlich von jemandem implementiert? Ich habe versucht, eine Komponente zu implementieren, die nur den HTML-Kommentar rendert, aber es scheint nicht zu funktionieren.

FYI, das Rewrite, an dem wir arbeiten (#6170), unterstützt bereits Fragmente. Sie können unseren Fortschritt in #7925 und auf http://isfiberreadyyet.com verfolgen.

Die bloße Tatsache, dass das <table> -Element bestimmte Elemente nicht darstellen kann, ist Grund genug, diese Funktion hinzuzufügen, um mit Web-APIs kompatibel zu sein.

EDIT: Ah, Fragmente! Ich freue mich auf sie.

@trusktr

Wie schon im allerersten Beitrag in diesem Thread erwähnt:

Hinweis der Betreuer:

Wir wissen, dass dies ein Problem ist, und wir wissen genau, welche Probleme gelöst werden können . Wir wollen das auch, aber es ist ein großes Problem mit unserer aktuellen Architektur. Zusätzliche Kommentare, die den Wunsch nach dieser Funktion äußern, sind nicht hilfreich.

😉

Meine Güte, ich muss damit aufhören.

Ich habe dies positiv bewertet, wollte aber einen gültigen Anwendungsfall teilen. Angenommen, ich habe 3 Schaltflächen, für die ich ein flüssiges CSS-Layout haben möchte (links, Mitte, rechts). Die linke Schaltfläche ist immer sichtbar, aber die anderen beiden sind bedingt sichtbar. In React (insbesondere React Native) verwende ich seine Flexbox und rendere sie wie folgt:

[ Left ] { renderCenterAndRightButtons(this.state.someFlag) }

Die mittlere und die rechte Schaltfläche werden nicht richtig positioniert, da sie in eine einzelne Ansicht eingeschlossen sind.

Ja, ich könnte die mittlere und die rechte Schaltfläche auf ihre eigenen Methoden aufteilen, aber das würde viel redundanten Code einführen, da sie viel Verhalten teilen.

[ Left ] { renderCenterButton(this.state.someFlag) } { renderRightButton(this.state.someFlag) }

Wie oben erwähnt, sind uns bereits Anwendungsfälle für diese Funktion bekannt und wir arbeiten hart daran, sie zu unterstützen. (Es gibt bereits ein halbes Dutzend Leute oben, die das Flexbox-Problem ansprechen.) Da es nicht so aussieht, als würde eine weitere Diskussion produktiv sein, schließe ich dies. Wir werden aktualisieren, wenn wir Neuigkeiten über die neue Implementierung haben.

Ich denke, wir können das schließen.

Das Zurückgeben von Arrays von Komponenten wird seit React 16 Beta 1 unterstützt, das Sie jetzt ausprobieren können .

Es gibt immer noch einige Einschränkungen (SSR-Unterstützung ist noch nicht bereit), aber wir verfolgen sie in #8854 und werden sie vor der endgültigen Version 16 beheben.

Danke an alle für euer Feedback!

DANKE DANN

🍾🍾🍾

🦏

@gaearon Tolle Verbesserung! Unterstützt es reine Textknoten?

Ja, es unterstützt auch die Rückgabe von Zeichenfolgen.

Darf ich fragen wie das funktionieren soll?

Ich hatte gehofft, es würde uns ermöglichen, 2 benachbarte XJS-Elemente zu rendern, aber wenn ich return ["foo", "bar"] (etwas Nützlicheres ;) mache, bekomme ich die erwarteten bundle.js:66656 Warning: Each child in an array or iterator should have a unique "key" prop.

War das Feature also eine Möglichkeit, eine echte Liste nicht mit einem irrelevanten Element zu umgeben?

War das Feature also eine Möglichkeit, eine echte Liste nicht mit einem irrelevanten Element zu umgeben?

Ja, eine Möglichkeit, mehrere Elemente aus einem Rendering bereitzustellen. (Weitere Informationen finden Sie im Erstausgabenbeitrag.)

Wenn bekannt ist, dass alle Ihre Array-Elemente Zeichenfolgen sind, verbinden Sie sie einfach und geben Sie eine einzelne Zeichenfolge zurück. Wenn nicht, können Sie entweder diese Warnung essen oder herausfinden, was zu tun ist, um sie in Elemente zu verpacken, damit sie verschlüsselt werden können, um den DOM-Abgleich zu verbessern, so wie Sie es getan hätten, wenn Sie ein Array von Zeichenfolgen in ein anderes Element in JSX eingefügt hätten.

@diligiant , das ['foo', 'bar'] zurückgibt, ist für dieses Problem nicht relevant. Sie konnten und können es immer noch nicht return <div>{['foo','bar']}</div> Jedes untergeordnete Element in einem Array sollte eine 'Schlüssel'-Prop haben, unabhängig davon, ob es sich in einem internen jsx-Tag wie <div> befindet oder zurückgegeben wird. Was Sie jetzt tun können, ist:

return [<div key='1'>foo</div>, <span key='2'>bar</span>];

Es beseitigt eine große Einschränkung in der Reaktion.

Übrigens, wenn Sie ['foo', 'bar'] zurückgeben, erhalten Sie eine Warnung, keinen Fehler, und um diese Warnung zu entfernen, können Sie diese Zeichenfolgen einfach verbinden, oder wenn es sich um jsx-Tags und nicht um Zeichenfolgen handelt, können Sie ihnen eine Schlüsselstütze hinzufügen. Es gibt also keine Einschränkung bei der Rückgabe von Arrays.

@JesperTreetop danke.
@sassanh , aus Ihrem Beispiel scheint es, dass ich zu "schüchtern" war, um Schlüssel "nur" zu verwenden, um eine (semantisch) nutzlose Umgebung zu vermeiden <div> . Meinst du, ich sollte weitermachen und dass es keine wirkliche Leistungseinbuße gibt? Das wäre in der Tat eine ECHTE Verbesserung!

@diligiant Ich bezweifle, dass dies zu Leistungseinbußen führt, aber Sie benötigen kein umgebendes nutzloses div , es sei denn, es handelt sich um umgebende Zeichenfolgen, und wenn es sich um umgebende Zeichenfolgen handelt, können Sie Array überhaupt vermeiden und Zeichenfolgen verbinden. Wenn es sich nicht um Zeichenfolgen handelt, können Sie den Schlüssel zur Komponente hinzufügen. Wenn Sie beispielsweise zwei Komponenten Foo und Bar haben, können Sie [<Foo key='foo'/>, <Bar key='bar'/>] zurückgeben und müssen weder Ihre Komponenten (wie immer) noch Ihr Array (dank In dieser neuen Version mussten Sie das Array vor 16) umgeben.

@sassanh cool dann. Natürlich war mein Anwendungsfall mit mehreren Komponenten. Glücklich!! ;)

Eigentlich kommt es mir seltsam vor, dass wir vor fehlenden Schlüsseln warnen, wenn alle Elemente Strings sind. Das würde ich von uns nicht erwarten. Ist dieses bestehende Verhalten in 15 vorhanden, wenn Zeichenfolgen in einem div sind? Wenn nicht, sollten wir es in 16 für Strings der obersten Ebene beheben (da es unmöglich ist, ihnen Schlüssel zu geben).

@gaearon Entschuldigung, mein Beispiel war irreführend: Ich meinte Komponenten.

Ich habe überprüft und unter -beta.5 gibt React keine Warnung aus, wenn ein Array mit mehreren Strings gerendert wird.

Trotzdem bin ich verwirrt über die key -Anforderung, wenn ein Array gerendert wird, nur um eine umgebende Komponente zu vermeiden. Ich verstehe und es ist nichts, aber es wird wahrscheinlich Tonnen von Fragen zu SO aufwerfen (ich habe jedoch nichts Besseres anzubieten …)

Und zum Schluss nochmals vielen Dank.

Diese Warnung ist genau die gleiche wie bei jeder anderen Verwendung von Arrays von Komponenten, da sie auf genau die gleiche "zusätzliche Arbeit" für den Reconciler hinausläuft und somit auf genau die gleiche potenzielle Optimierung durch das Setzen eines key . Für mich wäre die Überraschung, wenn Arrays von Komponenten abhängig davon unterschiedlich behandelt würden, und ich stelle mir vor, dass dies auch einige Stack Overflow-Fragen aufwerfen würde. Ganz zu schweigen davon, dass ich denke, dass es mit einigem Overhead verbunden wäre, nur um überhaupt den Überblick zu behalten.

.. und die meiste Zeit werde ich ein Array von einer Funktion zurückgeben, ich möchte die key Warnung an Ort und Stelle haben. Es scheint, dass die Zeiten, in denen Sie die Warnung nicht möchten, die Minderheit sind, und React kann nicht wissen, ob es angebracht ist, nicht zu warnen.

Die Warnung ist notwendig, da das Fehlen von Schlüsseln zu Korrektheitsproblemen führen kann, nicht nur zu Leistungsproblemen. Dies wird in vielen anderen Fragen erklärt, in denen gefragt wird, warum Schlüssel notwendig sind, also ermutige ich Sie, nach ihnen zu suchen und diese Diskussionen zu lesen. Ich stimme zu, dass die Dokumentation diesbezüglich klarer sein könnte, und wir werden uns das wahrscheinlich das nächste Mal ansehen, wenn wir einen Dokumentenänderungssprint durchführen.

Es gibt keine konzeptionellen Unterschiede zwischen Arrays, die direkt vom Rendern zurückgegeben werden, und Arrays innerhalb eines div. Es gibt also keinen Grund, warum es in einem Fall eine Schlüsselwarnung geben sollte, in dem anderen aber nicht. Sie müssen auf die gleiche Weise funktionieren, da beide von den gleichen Problemen betroffen sind, wenn die Schlüssel fehlen.

Wir verstehen jedoch, dass es lästig ist, Schlüssel für statische Inhalte anzugeben. Genauso wie Sie keine Schlüssel angeben, wenn Sie eine JSX-Struktur schreiben, in der Kinder statisch bekannt sind (und daher nie neu geordnet werden), wäre es schön, eine Möglichkeit zu haben, dies mit Arrays zu tun.

In Zukunft könnten wir dies lösen, indem wir explizite Unterstützung für Fragmente in JSX mit Syntax wie der folgenden hinzufügen:

return (
  <>
    <div>child 1</div>
    <div>child 2</div>
  </>
);

Es könnte ein Array erzeugen, aber den Kindern implizit numerische Indizes zuweisen, da wir in diesem Fall wissen , dass sie niemals neu ordnen können. Diese Garantie, die durch den untergeordneten JSX-Ausdruck gegeben wird, ist genau das, was es uns ermöglicht, ohne die Angabe von Schlüsseln in normalem JSX-Code davonzukommen, wo ein div mehrere untergeordnete Elemente haben könnte.

Aber wir haben diese Syntax noch nicht. Im Moment ist dies also eine bekannte Einschränkung.

@JesperTreetop & @zwily , @gaearon hat es viel besser erklärt als ich ;)

Sobald Sie wissen, ist es keine große Sache, aber da wir alle wollen, dass React gedeiht, habe ich nur gesagt …

@gaearon Gibt es ein weiteres Problem für den <> -Syntaxvorschlag, das wir uns ansehen können, anstatt dieses Problem weiter zu diskutieren? Ich habe mich umgesehen, aber ich konnte keinen finden.

@smrq +1 zur Frage – Ich verfolge alles über diese unangenehmen Einschränkungen (Eins-zu-Eins- rendrer() -Ergebnis, Schlüssel und JSX-Syntax oder -Fragmente), aber das einzige Ticket, das ich kenne, ist https://github.com/ facebook/jsx/issues/65

Ich nehme auch an, dass Fasern Probleme mit Schlüsseln überhaupt lösen werden – aber es sieht so aus, als wäre es ein unerfüllter Traum

Schlüssel sind kein "Problem". :) Sie sind ein grundlegender und notwendiger Bestandteil jedes Ansichtsframeworks, mit dem Sie dynamische Listen erstellen können.

Siehe https://facebook.github.io/react/tutorial/tutorial.html#keys für eine ausführlichere Erklärung.

@spicyj tatsächlich ist es ein «Problem», da es zu erhöhten Energieausgaben von Entwicklern führt und es grundsätzlich möglich ist, das View-Framework ohne eine solche Anforderung zu programmieren (z. B. https://github.com/dfilatov/vidom)

es besteht grundsätzlich die Möglichkeit Viewframework ohne solche Anforderung zu programmieren (zB https://github.com/dfilatov/vidom)

vidom verwendet jedoch Schlüssel in Sammlungen. Es könnte technisch ohne es funktionieren, aber es wäre wahrscheinlich viel langsamer. React könnte technisch auch ohne Schlüssel funktionieren, aber es wäre ziemlich unerwartet herauszufinden, dass die Hälfte Ihrer Komponenten aktualisiert werden muss, wenn Sie ein einzelnes Element aus einer Liste entfernen. Bei Schlüsseln wird nur ein Element demontiert.

@goto-bus-stop vidom kann Schlüssel verwenden, aber sie sind nicht erforderlich und ohne sie können nur wirklich große Fälle mit vielen Updates zu echten Leistungsproblemen führen

Daher betrachte ich diesen Teil als möglich optional (wie zum Beispiel shouldComponentUpdate ), der in Einzelfällen für Leistungsoptimierungen verwendet werden kann

@veged Beispiel für Vidom, das ohne Schlüssel kämpft .

Es hat keine Ahnung, dass es die Elemente neu anordnen soll, also verwirft es die Instanzen bei jedem Rendering der Root-Komponente.

als jemand, der mit dem Virtual-Dom-Raum ziemlich vertraut ist [1]. Ich kann das sagen:

  1. Schlüssel sind für vorhersagbare Dom- und Zustandsaktualisierungen zwischen ähnlichen Geschwistern erforderlich.
  2. Schlüssel sind normalerweise keine Optimierung, und tatsächlich sind sie normalerweise das Gegenteil.

[1] https://github.com/leeoniya/domvm

Das eindeutige Problem hier (wie von @gaearon beschrieben) ist jedoch eine vollständig statische Verwendung von Arrays und der Unterschied zwischen statischen Arrays und statischen JSX-Fragmenten

@brigand O habe keinen Zweifel daran, dass die Neuordnung von Komponenten mit vollem Status einige Probleme verursachen kann ;-) aber zwinge alle anderen Fälle (meiner Meinung nach mehr davon), dafür zu kämpfen ... sieht kontrovers aus

Schlüssel sind wichtig für React. Auch wenn sie in einigen Fällen keine Rolle zu spielen scheinen (z. B. weil die folgenden Komponenten alle zustandslos sind), hindert Sie nichts daran, eine zustandsbehaftete Komponente (oder sogar eine einfache DOM-Eingabe) irgendwo ein paar Ebenen tiefer hinzuzufügen in ein paar Monaten. Bis dahin könnten Sie vergessen, dass Sie keine Schlüssel haben, und Neubestellungen können dazu führen, dass der Status (oder Eingabewert) einem falschen Element zugeordnet wird.

Aus diesem Grund empfehlen wir Ihnen, überall Schlüssel für dynamische Listen anzugeben. Wenn Sie dies nicht tun, führt dies zu sehr schwer nachzuvollziehenden Fehlern, und wir denken, dass es besser ist, zusätzliche zehn Sekunden mit der Angabe des Schlüssels zu verbringen, als zehn Stunden mit dem Debuggen zu verbringen, warum der Zustand einer Komponente mehrere Ebenen darunter in einem Sonderfall durcheinander gebracht wird.

Ich stimme voll und ganz zu, dass es unpraktisch ist, Schlüssel anzugeben, wenn bekannt ist, dass die Liste statisch ist und niemals neu geordnet wird. Sie können dies gerne im JSX-Repo diskutieren. Wenn Sie dafür kein Problem finden, können Sie dort gerne ein neues erstellen.

Da dieser Thread viele Abonnenten hat und die Funktion implementiert wurde, möchte ich ihn sperren, um zu vermeiden, dass viele Leute mit Benachrichtigungen spammen. Ich hoffe, dass die obigen Klarstellungen Ihre Bedenken ausräumen, aber wenn nicht, können Sie gerne ein neues Thema für weitere Diskussionen zu einem bestimmten Thema erstellen.

@smrq hat ein Vorschlagsproblem für die <> -Syntax im jsx-Repo erstellt: https://github.com/facebook/jsx/issues/84.

Wir haben gerade die Unterstützung für einen neuen React.Fragment -Export und die zugehörige <> -Syntax veröffentlicht:
https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen