Feliz: [<reactcomponent>] vs React.functionComponent in React Refresh</reactcomponent>

Erstellt am 25. Nov. 2020  ·  10Kommentare  ·  Quelle: Zaid-Ajaj/Feliz

Hallo Freund,

Als naiver Möchtegern-Frontend-Entwickler kam ich zu einem interessanten Verhalten:

Basierend auf Ihren Dokumenten bevorzuge ich die Verwendung von React.functionComponent zum Erstellen von Komponenten, da ich zum besseren Debuggen auch den Namen der Komponente angeben kann. Lustige Sache kommt mit React Refresh.

Code wie dieser löst bei jeder Codeänderung immer ein erneutes Laden der gesamten Seite aus:

let subView = React.functionComponent("SubView", fun () ->
    Html.text "Hello from sub"
)

let topView = React.functionComponent("TopView", fun () ->
    Html.div [ Html.div "Hello from top"; subView () ]
)

image

Wenn Sie jedoch eine Root-Komponente mit [<ReactComponent>] haben, funktioniert die Aktualisierung ohne vollständige Aktualisierung hervorragend.

let subView = React.functionComponent("SubView", fun () ->
    Html.text "Hello from sub"
)

[<ReactComponent>]
let topView () = Html.div [ Html.div "Hello from top"; subView () ]

Ist es ein Fehler? Ist es ein Fehler in der schicken schwarzen Krawatte, auch bekannt als Feature? Ist alles meine Schuld, weil ich den Unterschied zwischen dem ReactComponent-Attribut und der React.functionComponent-Funktion nicht verstehe? 😄

Vielen Dank für jede Art von Hilfe, um besser zu verstehen.

question

Hilfreichster Kommentar

Beeindruckend! Einfach wow! Dumme Person stellt dumme Fragen und kluge Antworten mit drei A4-Blättern voller relevanter Informationen und Erklärungen. 🤯 Du rockst nur, Mann! Vielen Dank! ❤️ Jetzt verstehe ich und werde stattdessen Attribut verwenden.

Wird immer noch empfohlen, Komponenten irgendwie zu benennen (wie wir es mit dem ersten Parameter von React.functionComponent getan haben), oder ist dies für den Attributansatz nicht mehr erforderlich?

Alle 10 Kommentare

Das Attribut wird in Zukunft der richtige Weg sein und ist erforderlich, damit die Reaktionsaktualisierung funktioniert. Zumindest war das so, aber ich dachte, @ Zaid-Ajaj hat das geklärt, so dass es keinen Unterschied gab?

Hallo Roman,

Dies ist eine wirklich gute Frage, auf die es keine kurze Antwort gibt.

Sobald ich meine Internetprobleme zu Hause gelöst habe, werde ich das Streaming wieder aufnehmen, wo ich dies in qualvollen Details erkläre

Basierend auf Ihren Dokumenten bevorzuge ich die Verwendung von React.functionComponent zum Erstellen von Komponenten, da ich zum besseren Debuggen auch den Namen der Komponente angeben kann. Lustige Sache kommt mit React Refresh.

Zunächst möchte ich darauf hinweisen, dass sich die Dokumentation in einem unglücklichen Übergangszustand befindet: Im Grunde genommen veraltet mit dem neuesten Feliz und [<ReactComponent>] Güte, bis wir die Probleme mit dem Compiler-Plugin lösen und den von Fable verwendeten AST stabilisieren . Ich versuche zu sagen, dass die Dokumente React.functionComponent nicht bevorzugen. Wenn Sie Fable 3 verwenden, sollten Sie stattdessen [<ReactComponent>] verwenden.

Dies hängt damit zusammen, wie der Javascript-Code generiert wird. Betrachten Sie nun diesen Teil des Reaktionscodes:

const App = ({ title }) => {
  return (
    <h1>{title}</h1>
  )
};

<App title="My React Application" />

Dieser JS (der eigentlich JSX ist) desugiert bis auf den folgenden JS-Code

import { createElement } from 'react'

const App = ({ title }) => {
  return createElement("h1", null, title);
};

// <App /> compiles to a call to createElement
createElement(App, { title: "My React Application" })

Es ist sehr wichtig zu beachten, dass die Initialisierung der App -Komponente über <App ... /> zu einem Aufruf von createElement von JS kompiliert wird.

Es ist aus zwei Gründen wichtig:

  • Es trennt die Definition der Komponente von ihrer Erstellung
  • Es erlaubt App , ein statischer Wert zu sein (Identität ist reserviert, die React verwendet)

Die Art und Weise, wie React.functionComponent implementiert wird, ist für React "schlecht", da Definition und Erstellung auf einmal kombiniert werden. Dieser F # Code

let app React.functionComponent("App", fun (props: {|  tite: string |}) -> Html.h1 props.title)

Ist irgendwie gleichbedeutend mit sagen

let app = 
  let render(props: {|  tite: string |}) = 
    let renderFn props= Html.h1 props.title
    createElement(renderFn , props)
  render.displayName <- "App"
  render

Dies ist "schlecht", da createElement eine Komponente rendert, die bei jedem Aufruf dynamisch definiert wird und die displayName der Funktion mutiert, anstatt den Funktionsnamen selbst zu verwenden.

Dieser Syntaxzucker, den React.functionComponent verwendet, wirkt sich nicht auf das Laufzeitverhalten von React aus. Deshalb können wir ihn problemlos zum Erstellen der React-Anwendung verwenden. Die Probleme schleichen sich ein, wenn das TOOLING um React-Anwendungen beginnt, den generierten Code zu analysieren: Webpack, Babel, React-Refresh sind alles Tools, die den generierten Code suchen und hier und da etwas Magie einbringen, um den Austausch heißer Module zu ermöglichen, aber mit React.functionComponent ist nicht möglich, da der generierte Code nicht mit der Art und Weise übereinstimmt, wie React-Anwendungen normalerweise beim Schreiben von JS erstellt werden, und viele der Tools rund um React Annahmen treffen, die auf der Tatsache beruhen, dass der Code gemäß dem Standard geschrieben wurde Reagieren Sie darauf, als von einem Werkzeug erzeugt.

Die Lösung für diese Probleme findet sich in Fable 3, wo wir die Kompilierung des Codes über Compiler-Plugins anpassen dürfen. Wenn Sie diesen F # Feliz-Code in Fable 3 berücksichtigen

[<ReactComponent>]
let app (title: string) = Html.h1 title 

app "My  React Application"

Dann wird es auf das Äquivalent dieses JS kompiliert (nicht genau, weil mehr Magie)

const App = (props) { 
   const title = props.title
   return createElement("h1", null, title)
}

createElement(App, { title: "My  React Application" })

Jetzt wird dieser generierte Code so angepasst, dass er den Erwartungen von React Tooling entspricht:

  • Definitionen und Kreationen von Funktionskomponenten sind getrennt
  • Komponenten werden als Großbuchstaben definiert (ja, dies ist ebenfalls erforderlich und das Compiler-Plugin schreibt die Definition automatisch neu).
  • Eingabeparameter werden automatisch in React-Requisiten übersetzt

Durch diese Kombination funktioniert die Aktualisierung von React und die Erfahrung von Feliz kommt der von nativem JS oder TS sehr nahe. Ich hoffe, das klärt die Verwirrung. Wenn Sie weitere Fragen haben, lassen Sie es mich einfach wissen 😉

Beeindruckend! Einfach wow! Dumme Person stellt dumme Fragen und kluge Antworten mit drei A4-Blättern voller relevanter Informationen und Erklärungen. 🤯 Du rockst nur, Mann! Vielen Dank! ❤️ Jetzt verstehe ich und werde stattdessen Attribut verwenden.

Wird immer noch empfohlen, Komponenten irgendwie zu benennen (wie wir es mit dem ersten Parameter von React.functionComponent getan haben), oder ist dies für den Attributansatz nicht mehr erforderlich?

Jetzt verstehe ich und werde stattdessen Attribut verwenden.

Genial! Lassen Sie mich, wenn Sie auf ein Problem stoßen - das einzige Problem, das Sie im Moment beachten müssen, ist die Verwendung eines Datensatztyps, da Eingabestützen für die React-Aktualisierung nur ein wenig problematisch sind, sodass Sie stattdessen einen anonymen Datensatz oder primitive Parameter verwenden können. Ich hoffe, dass das Problem bald behoben ist, damit ich [<ReactComponent>] ohne Einschränkungen dokumentieren kann.

Wird immer noch empfohlen, Komponenten irgendwie zu benennen (wie wir es mit dem ersten Parameter von React.functionComponent getan haben), oder ist dies für den Attributansatz nicht mehr erforderlich?

Nein, die einzige Voraussetzung ist, dass die Komponenten als Großbuchstaben kompiliert werden. Dies ist eines der Dinge, die [<ReactComponent>] mit der Funktionsdefinition macht: smile: Sie können die Implementierung hier durchführen

@Dzoukr Der einzige Grund, Namen für Ihre Reaktionskomponenten zu verwenden, besteht darin, das Debug-Tooling zu

@Shmew Yup , aber es gibt keine Überlastung des ReactComponent-Konstruktors für das Hinzufügen eines solchen Namens, weshalb gefragt wurde.

Fahren Sie also mit den Fragen [<ReactComponent>] vs functionComponent : Hooks!

Ich habe eine Komponente, die einen Status initialisieren muss. Zum Glück haben wir viele feine Haken zur Verfügung! Ich schreibe das:

[<ReactComponent>]
let Entrypoint() =
    let drawing, updateDrawing = React.useState(Deferred.HasNotStartedYet)
    let loader = React.useDeferredCallback((fun () -> loadDrawing()), updateDrawing)

    React.useEffect(loader, [||])
    // etc

Leider ist meine Konsole traurig und voller Fehler, wenn ich versuche, dies auszuführen:

Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.
    React 

Ich habe die obigen Schritte zum Reagieren von Debugging durchlaufen. keine scheint wahr zu sein. Sollte das funktionieren? Ist das nur eine Fable 3-Sache? (Ich benutze immer noch Fable 2.)

Ich verstehe, dass das Reactcomponent-Attribut Fable 3 benötigt, um zu funktionieren, da es sich um ein Fable 3-Compiler-Plugin handelt

@landy ah, das würde es sicher tun. Lass mich Fable 3 zum Laufen bringen, melde mich gleich

Hallo! Ja, das hat mich repariert - ich habe diese PR als Leitfaden für die Konvertierung verwendet.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

alfonsogarciacaro picture alfonsogarciacaro  ·  11Kommentare

nojaf picture nojaf  ·  4Kommentare

heimeshoff picture heimeshoff  ·  6Kommentare

7sharp9 picture 7sharp9  ·  7Kommentare

Zaid-Ajaj picture Zaid-Ajaj  ·  8Kommentare