Fable: Entwerfen der React Helper API

Erstellt am 19. März 2016  ·  3Kommentare  ·  Quelle: fable-compiler/Fable

Ich entwerfe derzeit eine API, um die Interaktion mit React aus F# zu erleichtern, und die Sprachkombination bietet mehrere interessante Möglichkeiten für die statische Überprüfung. Allerdings gibt es erwartungsgemäß einige raue Enden und ich habe Zweifel, wie die Eigenschaften in einem React DOM-Element definiert werden sollen. Aktuell haben wir:

Option 1 : Dynamische Eigenschaften

module R = Fable.ReactHelper
R.input [
    "type" ==> "text"
    "placeholder" ==> "Your name"
    "value" ==> x.state.author
    "onChange" ==> x.handleAuthorChange
] []

Dies ist die flexibelste Option, da wir jede Eigenschaft in einem einfachen JS-Objekt übergeben können. Dank Inlining-Funktionen brauchen wir hier nicht createObj und sparen uns auch einige geschweifte Klammern. Wenn Sie denken, dass ==> zu ausführlich ist, ist das Kürzen ebenfalls trivial: let inline (=>) a b = a ==> b

Das Problem ist, dass wir keine statische Überprüfung oder automatische Vervollständigung für die Eigenschaften haben. Daher überlege ich, stattdessen ein Lambda zu verwenden. Aber jetzt müssen wir uns entscheiden, woher wir die Signatur bekommen. Zuerst habe ich das aus den IntrinsicElements genommen, die in der React-Definitionsdatei definiert sind :

Option 2 : Mutieren von HTMLElement-Eigenschaften

R.input (fun p ->
    p.``type`` <- "text"
    p.placeholder <- "Your name"
    p.value <- unbox x.state.author
    //p.onchange <- unbox x.handleAuthorChange
    p?onChange <- x.handleAuthorChange
) []           

Jetzt haben wir statische Überprüfung und automatische Vervollständigung für die Eigenschaften, was sehr schön ist. Beachten Sie jedoch, dass einige Reibungen mit den Typdefinitionen auftauchen und mit unbox gelöst werden müssen. Das größte Problem bei diesem Ansatz besteht darin, dass, obwohl die TypeScript-Definition die Standard-DOM-Elemente verwendet, einige Attribute in React eine andere Schreibweise haben. Im obigen Beispiel funktioniert die Einstellung von onchange nicht, daher müssen wir onChange dynamisch festlegen. Dies bricht fast alle Vorteile der statischen Überprüfung :(

Unsere nächste Option besteht dann darin, stattdessen React.HTMLAttributes zu verwenden, um sicherzustellen, dass wir die richtige Schreibweise verwenden:

Option 3 : Mutieren der React.HTMLAttributes-Eigenschaften

R.input (fun p ->
    p.``type`` <- Some "text"
    p.placeholder <- Some "Your name"
    p.value <- unbox x.state.author
    p.onChange <- unbox x.handleAuthorChange
) []

Ok, alle Eigenschaften haben die von React erwartete Schreibweise, aber wir stehen jetzt vor anderen Problemen: Zuerst multiplizieren sich die Reibungen mit der Signatur, da alle Eigenschaften als optional definiert sind und andere benutzerdefinierte Typescript-Elemente wie gelöschte Unionstypen oder benutzerdefinierte Funktionen verwendet werden; und zweitens hatten wir in der vorherigen Option die spezifischen Attribute für input Tags, aber hier hat jedes HTML-Element dieselben Attribute. Dies kann jedoch immer noch die beste Option sein.

Es gäbe eine vierte Option, aber ich denke nicht sehr darüber nach:

Option 4 : Verwenden eines benutzerdefinierten HTMLAttributes-Datensatzes

R.input (fun p ->
    { p with
        ``type`` = Some "text"
        placeholder = Some "Your name"
        value = unbox x.state.author
        onChange = unbox x.handleAuthorChange
}) []

Dies ist wahrscheinlich die idiomatischste in F#, aber die Einrückungsregeln werden komplizierter ( { p with kann nicht in die erste Zeile gesetzt werden) und wir haben hier keine automatische Vervollständigung, um die Eigenschaften von p , soweit ich weiß. Am wichtigsten ist, dass die Übernahme dieses Stils das Erstellen eines benutzerdefinierten Datensatzes für HTMLAttributes erfordern würde, da die von TypeScript als Schnittstellen geparst werden (dafür gibt es gute Gründe), sodass dies einen zusätzlichen Schritt bei der Pflege der Fable bedeuten würde importieren .

Hier sind die Optionen, um die Entscheidung zu treffen, und ich würde gerne Ihre Meinung dazu hören. Ich weiß, dass es möglich ist, der API mehrere Optionen hinzuzufügen, aber dies würde es für Neulinge wahrscheinlich verwirrender machen und ich würde es vorziehen, es zunächst einfach zu machen. Vielen Dank für Ihre Hilfe im Voraus!

discussion

Hilfreichster Kommentar

Möglichkeit 5.
Option 1 erweitern, um typisierte Attribute hinzuzufügen. Ich habe früher eine ähnliche API für FunScript erstellt.
https://github.com/FractalProject/Fractal.Sample/blob/master/client/App.fsx#L65 -L74
https://github.com/FractalProject/Fractal/blob/master/src/Fractal.DOM.fs

Möglichkeit 6.
Werden Sie verrückt und erstellen Sie Berechnungsausdrücke mit benutzerdefinierten Schlüsselwörtern.

Alle 3 Kommentare

Möglichkeit 5.
Option 1 erweitern, um typisierte Attribute hinzuzufügen. Ich habe früher eine ähnliche API für FunScript erstellt.
https://github.com/FractalProject/Fractal.Sample/blob/master/client/App.fsx#L65 -L74
https://github.com/FractalProject/Fractal/blob/master/src/Fractal.DOM.fs

Möglichkeit 6.
Werden Sie verrückt und erstellen Sie Berechnungsausdrücke mit benutzerdefinierten Schlüsselwörtern.

Für Neulinge denke ich, dass Option 4 die beste ist, auch keine magischen Fäden und es hält die Sache unveränderlich.

Danke für den Vorschlag, @Krzysztof-Cieslak! Zuerst hatte ich befürchtet, dass dies mehr Wartungsarbeiten erfordern würde, aber nach einiger Überlegung wurde mir klar, dass dies die beste Option war. Ich habe auf Ihrem Code aufgebaut und ein Skript geschrieben, um (teilweise) das Hilfsmodul zu generieren:
https://github.com/fsprojects/Fable/blob/master/samples/browser/react/public/Fable.ReactHelper.fs

Der Rendercode ist jetzt mit vollständiger statischer Überprüfung viel schöner :)
https://github.com/fsprojects/Fable/blob/master/samples/browser/react/public/components.fs#L104 -L124

Am React Helper ist noch zu arbeiten, aber ich schließe das Problem vorerst. Ich danke Ihnen allen für Ihre Hilfe!

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen