Feliz: Pendapat Anda tentang ide v2?

Dibuat pada 17 Mar 2021  ·  9Komentar  ·  Sumber: Zaid-Ajaj/Feliz

Halo teman,
sebagai pengguna harian Feliz (dan Feliz.Bulma memang) saya selalu berjuang dengan bersarang prop.children yang membuatnya entah bagaimana lebih jelek bagi saya. Saya ingin tahu pendapat Anda tentang proposal v2 di mana kami akan memiliki:

Html.div [
    prop.className "myClass"
    Html.div "Nested"
]

Mungkin sesuatu seperti itu bahkan tidak mungkin, tapi aku melihat pekerjaan @alfonsogarciacaro 's di Feliz.Engine dan tampaknya begitu menggoda untuk memiliki alat peraga dan anak-anak pada tingkat yang sama. 😄

discussion

Komentar yang paling membantu

Petisi untuk mengubah judul untuk menunjukkan topik diskusi? 😆

@Dzoukr Ada diskusi sebelumnya tentang ini -- saya pasti di pihak Anda.

Fungsi pembantu tidak ideal karena mereka mengembalikan sintaks daftar ganda yang canggung, pada dasarnya menghilangkan salah satu manfaat utama dari lib ini di tempat pertama, dan mereka tidak membantu dengan penggunaan prop nyata yang lebih dari sekedar div+kelas.

@Zaid-Ajaj Maukah Anda membuka ruang nama alternatif untuk menjelajahi area ini? Seperti Feliz.Experimental atau apa? Jadi namespace Feliz utama menjaga tujuan lapisan tipis di atas React sementara alternatif dapat mencoba pendekatan yang lebih berpendirian.

Bagaimanapun, saya suka sesuatu seperti ini untuk mempertahankan pengelompokan prop:

Html.div [
    props [
        prop.className "myClass"
    ]
    Html.div "Nested"
]

Penyarangan prop tampaknya lebih bersih daripada penyarangan elemen karena props tidak tunduk pada sarang tak terbatas seperti elemen. Wadah props akan berbagi antarmuka dengan elemen Html.* , memodelkan keduanya sebagai anak yang valid dari elemen yang mengandung.

Performa akan menjadi sesuatu yang harus diperhatikan tetapi saya tidak berpikir dampaknya diketahui tanpa mencoba. Siapa tahu, mungkin pekerjaan ekstra hanya terdengar menakutkan tetapi ternyata tidak signifikan dalam praktiknya dibandingkan dengan semua yang terjadi di render.

Semua 9 komentar

Menambahkan dukungan semacam ini akan membuat inferensi tipe jauh lebih permisif (saya bahkan akan mengatakan tidak berguna) karena dengan begitu kita akan memiliki Attribute = Properties = ReactElement . Pada dasarnya, semuanya akan diterima sebagai tipe yang sama...

Juga, untuk memungkinkannya, kita perlu menambahkan lapisan tambahan di atas React untuk memisahkan atribut dari anak-anak "secara manual" yang akan memengaruhi kinerja karena kita akan selalu memiliki langkah tambahan yang diperlukan. Ini juga akan meningkatkan ukuran bundel untuk menyimpan informasi yang diperlukan untuk membuat pemisahan.

Secara pribadi, saya bukan untuk fitur ini.

Saya memiliki perasaan campur aduk tentang pendekatan ini, terutama karena overhead runtime yang ditambahkan ke rendering. Saya juga lebih suka menyimpan gagasan ReactElement terpisah dari ReactAttribute . Jadi secara pribadi saya lebih suka API saat ini.

Dalam pengalaman saya, saya sering mendengar tentang masalah ini dari pengguna tetapi _only_ dalam konteks div dengan nama kelas dan anak-anak. Di mana respons saya yang biasa adalah menulis fungsi pembantu kecil yang memungkinkan Anda menulis sesuatu seperti ini atau yang serupa

div [ "myClass" ] [
  Html.div "nested"
]

Menurut saya tidak ada alasan untuk tidak menulis metode ekstensi Anda sendiri jika metode tersebut lebih sesuai dengan efek penerapan kelas atau properti lain yang sering digunakan seperti yang saya lakukan di sini dengan Material UI. Komposabilitas sangat mudah dengan F# tanpa membingungkan kompiler lebih lanjut atau mengurangi keamanan tipe.

[<AutoOpen>]
module MuiExtensions

open Feliz
open Feliz.MaterialUI

type Mui 
    with
    static member gridItem (children:seq<ReactElement>):ReactElement = 
        Mui.grid [
            grid.item true
            grid.children children
        ]

    static member gridItem (props:seq<IReactProperty>):ReactElement = 
        Mui.grid [
            grid.item true
            yield! props
        ]

Terima kasih untuk semua pendapat, saya hanya ingin alur diskusi. 👍 Saya juga memiliki pembantu saya sendiri seperti divClassed "myClass" [ children ] atau lebih, tetapi ingin tahu sudut pandang orang lain.

Ini sebenarnya bisa dilakukan sambil menjaga batasan tipe jika kita mengubah elemen React dari daftar menjadi ekspresi komputasi:

div {
    className "myClass"

    div { ... }
}

Implementasi CE akan meningkatkan ukuran basis kode, pasti membuatnya lebih sulit untuk dipelihara, dan menangani beberapa hal seperti primitif ketika alat peraga didefinisikan sedikit rumit/harus gagal pada kompilasi daripada selama pengembangan seperti sekarang:

// Would probably need to make the base builder generic so we can use a type restriction and define this DU for
// each element so we can properly restrict what types are valid as primatives
type ReactBuilderChild =
    | Child of ReactElement
    | Children of ReactElement list
    | Float of float
    | Int of int
    | String of string
    | None

    member this.GetChildren () =
        match this with
        | ReactBuilderChild.Children children -> children
        | _ -> failwith "Cannot combine children with primitive values."

type ReactBuilderState =
    { Children: ReactElement list
      Props: IReactProperty list } 

[<AbstractClass;NoEquality;NoComparison>]
type ReactBuilder () =
    [<EditorBrowsable(EditorBrowsableState.Never)>]
    member _.Yield (x: ReactElement) = { Children = ReactBuilderChild.Child x; Props = [] }
    [<EditorBrowsable(EditorBrowsableState.Never)>]
    member _.Yield (x: ReactElement list) = { Children = ReactBuilderChild.Children x; Props = [] }
    [<EditorBrowsable(EditorBrowsableState.Never)>]
    member _.Yield (x: float) = { Children = ReactBuilderChild.Float x; Props = [] }
    ...
    [<EditorBrowsable(EditorBrowsableState.Never)>]
    member _.Yield (x: unit) = { Children = ReactBuilderChild.None; Props = [] }

    [<EditorBrowsable(EditorBrowsableState.Never)>]
    member _.Combine (state: ReactBuilderState, x: ReactBuilderState) = 
        { Children = (state.Children.GetChildren()) @ (x.Children.GetChildren()); Props = state.Props @ x.Props }

    [<EditorBrowsable(EditorBrowsableState.Never)>]
    member _.Zero () = { Children = ReactBuilderChild.None; Props = [] }

    [<EditorBrowsable(EditorBrowsableState.Never)>]
    member this.For (state: ReactBuilderState, f: unit -> ReactBuilderState) = this.Combine(state, f())

    [<CustomOperation("className")>]
    member _.className (state: ReactBuilderState, value: string) =
        { state with Props = (Interop.mkAttr "className" value)::state.Props }

    [<CustomOperation("children")>]
    member _.children (state: ReactBuilderState, value: ReactElement list) =
        { state with Children = state.Children @ value }

    abstract Run : ReactBuilderState -> ReactElement

[<NoEquality;NoComparison>]
type DivBuilder () =
    inherit ReactBuilder()

    [<EditorBrowsable(EditorBrowsableState.Never)>]
    member _.Run (state: ReactBuilderState) = 
        match state with
        | { Children = ReactBuilderChild.None; Props = props } -> Interop.createElement "div" props
        | { Children = ReactBuilderChild.Children children } -> Interop.reactElementWithChildren "div" children
        | { Children = ReactBuilderChild.Float f } -> Interop.reactElementWithChild "div" f
        | _ -> ...

let div = DivBuilder()

Apa yang saya tidak yakin tentang, adalah bagaimana membuat Fable dengan benar mengkompilasi salah satu/semua pipa CE, serta membuat operasi dapat ditemukan (seperti saat ini dengan tipe prop ).

Petisi untuk mengubah judul untuk menunjukkan topik diskusi? 😆

@Dzoukr Ada diskusi sebelumnya tentang ini -- saya pasti di pihak Anda.

Fungsi pembantu tidak ideal karena mereka mengembalikan sintaks daftar ganda yang canggung, pada dasarnya menghilangkan salah satu manfaat utama dari lib ini di tempat pertama, dan mereka tidak membantu dengan penggunaan prop nyata yang lebih dari sekedar div+kelas.

@Zaid-Ajaj Maukah Anda membuka ruang nama alternatif untuk menjelajahi area ini? Seperti Feliz.Experimental atau apa? Jadi namespace Feliz utama menjaga tujuan lapisan tipis di atas React sementara alternatif dapat mencoba pendekatan yang lebih berpendirian.

Bagaimanapun, saya suka sesuatu seperti ini untuk mempertahankan pengelompokan prop:

Html.div [
    props [
        prop.className "myClass"
    ]
    Html.div "Nested"
]

Penyarangan prop tampaknya lebih bersih daripada penyarangan elemen karena props tidak tunduk pada sarang tak terbatas seperti elemen. Wadah props akan berbagi antarmuka dengan elemen Html.* , memodelkan keduanya sebagai anak yang valid dari elemen yang mengandung.

Performa akan menjadi sesuatu yang harus diperhatikan tetapi saya tidak berpikir dampaknya diketahui tanpa mencoba. Siapa tahu, mungkin pekerjaan ekstra hanya terdengar menakutkan tetapi ternyata tidak signifikan dalam praktiknya dibandingkan dengan semua yang terjadi di render.

@zanaptak Saya cukup menyukai ide itu karena seperti yang Anda katakan, alat peraga tidak cenderung bersarang terlalu dalam seperti anak-anak.


Pada topik pembantu dan sintaks daftar ganda

mereka tidak membantu dengan penggunaan prop nyata yang lebih dari sekedar div+class

let inline withProps elementFunction props (children: #seq<ReactElement>) =
    (prop.children (children :> ReactElement seq))
    :: props
    |> elementFunction

let myDiv = withProps Html.div

myDiv [ prop.className "myClass" ] [
    Html.div "Nested"
]

Anda bahkan dapat menentukan operator untuk menggunakan sintaks seperti "daftar ganda" dengan elemen apa pun jika Anda mau:

let inline (@+) elementFunction props =
    fun children -> withProps elementFunction props children

let inline (@++) elementFunction prop =
    fun children -> withProps elementFunction [ prop ] children

Html.div @+ [ prop.className "myClass" ]
<| [ Html.div "nested" ]

Html.div @++ prop.className "myClass"
<| [ Html.div "nested" ]

Ini adalah topik yang rumit karena apa yang "terlihat lebih baik" bisa jadi subjektif. Mungkin hal yang paling penting adalah menghindari perubahan yang rusak, tetapi jika Anda hanya ingin bereksperimen, Anda dapat menggunakan Feliz.Engine untuk itu, karena sangat mudah untuk menyesuaikannya dengan React. Seperti yang disebutkan dalam edisi lain, saya tidak ingin menerbitkan Feliz.Engine.React karena akan membingungkan memiliki dua paket "bersaing" yang serupa. Tetapi misalnya, jika Anda ingin memiliki semuanya pada level yang sama, Anda hanya memerlukan modul seperti ini (akan mudah untuk menyesuaikannya dengan memiliki properti dalam daftar terpisah juga):

// Dependencies:
// - Fable.React
// - Feliz.Engine.Event dependencies

open Fable.Core
open Fable.Core.JsInterop
open Feliz
open Fable.React

type Node =
    | El of ReactElement
    | Style of string * string
    | Prop of string * obj
    member this.AsReactEl =
        match this with
        | El el -> el
        | _ -> failwith "not an element"

let private makeNode tag nodes =
    let props = obj()
    let style = obj()
    let children = ResizeArray()
    nodes |> Seq.iter (function
        | El el -> children.Add(el)
        | Style(k, v) -> style?(k) <- v
        | Prop(k, v) -> props?(k) <- v
    )
    if JS.Constructors.Object.keys(style).Count > 0 then
        props?style <- style
    ReactBindings.React.createElement(tag, props, children) |> El

let Html = HtmlEngine(makeNode, str >> El, fun () -> El nothing)

let Svg = SvgEngine(makeNode, str >> El, fun () -> El nothing)

let prop = AttrEngine((fun k v -> Prop(k, v)), (fun k v -> Prop(k, v)))

let style = CssEngine(fun k v -> Style(k, v))

let ev = EventEngine(fun k f -> Prop("on" + k.[0].ToString().ToUpper() + k.[1..], f))

Tes:

let myEl = // Node
    Html.div [
        prop.className "myClass"
        Html.div "Nested"
    ]

let myElAsReactEl = myEl.AsReactEl // ReactElement 

Fungsi pembantu tidak ideal karena mengembalikan sintaks daftar ganda yang canggung.

@zanaptak Fungsi Helper tidak perlu mengambil dua daftar sebagai input, div [ "class" ] [ ] hanyalah contoh skenario umum yang terjadi untuk mengambil dua daftar. Fungsi-fungsi ini juga dapat menjadi komponen yang membuat tampilan Anda lebih sederhana

Todo.List [ for item in items -> Todo.Item item ]

Meskipun Anda secara teknis dapat membuat daftar tanpa batas, itu bukan idenya. Ada keseimbangan di sana dengan menggunakan fungsi atau komponen yang lebih kecil dalam kode UI Anda yang lebih besar.

Namun, idealnya Anda tidak perlu memecah kode sesering mungkin dan satu fungsi harus mudah dibaca karena memikirkan mengatur berbagai hal terkadang menghilangkan _flow_. Ini adalah masalah dengan DSL dari Fable.React di mana Anda harus _berpikir_ tentang bagaimana memformat sesuatu setiap saat. Feliz memperbaikinya dengan biaya dua tingkat bersarang children .

Sejujurnya, saya tidak tahu apa peluru perak itu. Seperti kata @alfonsogarciacaro

Ini adalah topik yang rumit karena apa yang "terlihat lebih baik" bisa jadi subjektif

Pada topik percobaan:

Apakah Anda akan membuka ruang nama alternatif untuk menjelajahi area ini? Seperti Feliz.Experimental atau apa? Jadi namespace Feliz utama menjaga tujuan lapisan tipis di atas React sementara alternatif dapat mencoba pendekatan yang lebih berpendirian.

Saat ini, tidak ada rencana untuk mempertahankan DSL yang berbeda dalam proyek Feliz. Saya sangat terbatas pada waktu/kapasitas OSS dan berharap dapat mengarahkan upaya untuk meningkatkan pendekatan saat ini: dokumentasi, sampel, dan perpustakaan ekosistem yang lebih teruji.

Karena itu, silakan bereksperimen dengan Feliz.Engine oleh @alfonsogarciacaro dan gunakan DSL yang lebih cocok untuk Anda.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat