Привет,
этот выпуск предназначен для того, чтобы поделиться своим опытом с Фелиз и Фелиз.Бульма.
Этот отзыв основан на преобразовании Fable Repl из Fable.React + Fulma в Feliz + Feliz.Bulma .
В первом разделе я составлю список всего, что мне понравилось или с чем были проблемы при использовании Feliz. Я сделаю нечто подобное для Fable.React и Fulma, потому что они не лишены хорошей и менее хорошей стороны.
Затем, во второй раз, я постараюсь объяснить, как прошел мой опыт с Фелиз и Фелиз.Бульма. Цель состоит в том, чтобы поделиться с вами, как моя точка зрения изменилась с течением времени и почему.
Важный
Я знаю, что предмет, который я анализирую, чувствителен и что-то меня пугает. Но, пожалуйста, не забудьте оставить комментарий в позитивном ключе.
Я попытался найти способ систематизировать свои отзывы, классические «плюсы и минусы» казались мне слишком ограниченными и агрессивными.
Вместо этого я буду использовать символы:
В одной записи может быть несколько символов :)
✔️ Feliz и Fable.React можно смешивать, потому что Feliz является слоем поверх Fable.React
✔️ Код удобнее делать отступы по сравнению с Fable.React, потому что у нас есть только один список. За таблицей легче следить.
Щелкните здесь, чтобы узнать подробности
** Fable.React + Фульма **
div [ ]
[ Hero.hero [ Hero.IsFullHeight ]
[ Hero.body [ ]
[ Container.container [ ]
[ img [ Src "img/fable-ionide.png"
Style [ Display DisplayOptions.Block
Width "auto"
Margin "auto" ] ]
br [ ]
Heading.h3 [ Heading.Modifiers [ Modifier.TextAlignment (Screen.All, TextAlignment.Centered) ] ]
[ str "Fable REPL" ]
Heading.p [ Heading.IsSubtitle
Heading.Is5
Heading.Modifiers [ Modifier.TextAlignment (Screen.All, TextAlignment.Centered) ] ]
[ str "is only available on desktop" ] ] ] ] ]
** Фелиз + Фелиз.Бульма **Html.div [
Bulma.hero [
hero.isFullHeight
prop.children [
Bulma.heroBody [
Bulma.container [
Html.img [
prop.src "img/fable-ionide.png"
prop.style [
style.display.block
style.width length.auto
style.margin length.auto
]
]
Html.br [ ]
Bulma.title3 [
text.hasTextCentered
prop.text "Fable REPL"
]
Bulma.subtitle5 [
text.hasTextCentered
prop.text "is only available on desktop"
]
]
]
]
]
]
✔️ Благодаря предыдущему пункту также легко перемещать код
✔️ строго типизированный API для свойств DOM
✔️ Строго типизированный API для блоков CSS и CSS через ICSSUnits
style.marginLeft (length.em 0.5)
style.width (length.percent (model.PanelSplitRatio * 100.))
✔️ Не загрязняет контекст, большинство вещей ниже Html.*
или Prop.*
✔️ ⚠️ Feliz предлагает возможность избежать шума в коде
Щелкните здесь, чтобы узнать подробности
Html.span "Fable REPL"
// instead of
// Feliz verbose version
span [
str "Fable REPL"
]
// Fable.React
span [ ]
[ str "Fable REPL" ]
// --------------------
Bulma.title4 "Fable REPL"
// instead of
// Feliz.Bulma verbose version
Bulma.title4 [
prop.text "Fable REPL"
]
// Fable.React
Headings.h4 [ ]
[ str "Fable REPL" ]
Поскольку существует несколько способов написать один и тот же код, мы не можем просто «прочитать» код. Иногда нам нужно сделать шаг назад, чтобы понять внешний контекст. Это также делает код менее «согласованным», потому что не все написано одинаково.Html.tr [
Html.th "Steps"
Html.th [
prop.className "has-text-right"
prop.text "ms"
]
]
⚠️ Он (пока) не поддерживает SSR
⚠️ Обнаружить перегрузку методов / свойств непросто (возможно, это ограничение Ionide, которого я не знаю)
Мне пришлось:
prop.text 2.0
когда у меня был float.⚠️ Усложните использование обратного вызова с более чем одним параметром. В Fable.REPL мне пришлось заставить uncurry использовать System.Func<_,_,_>
.
Щелкните здесь, чтобы узнать подробности
[<Erase>]
type editor =
/// <summary>Triggered when the Editor has been mounted</summary>
static member inline editorDidMount (f : System.Func<Monaco.Editor.IStandaloneCodeEditor, Monaco.IExports, unit>) = Interop.mkAttr "editorDidMount" f
Что дает этот код на вызывающей стороне:let private registerCompileCommand dispatch =
System.Func<_,_,_>(
fun (editor : Monaco.Editor.IStandaloneCodeEditor) (monacoModule : Monaco.IExports) ->
let triggerCompile () = StartCompile None |> dispatch
editor.addCommand(monacoModule.KeyMod.Alt ||| int Monaco.KeyCode.Enter, triggerCompile, "") |> ignore
editor.addCommand(monacoModule.KeyMod.CtrlCmd ||| int Monaco.KeyCode.KEY_S, triggerCompile, "") |> ignore
)
✔️ ⚠️ Feliz предоставляет перегрузки для облегчения жизни пользователей, но за это приходится платить.
Для prop.onChange
, например, 6 перегрузок в зависимости от того, что вы хотите слушать:
static member inline onChange (handler: bool -> unit)
static member inline onChange (handler: Event -> unit)
static member inline onChange (handler: File -> unit)
static member inline onChange (handler: File list -> unit)
static member inline onChange (handler: string -> unit)
static member inline onCheckedChange (handler: bool -> unit)
Это хорошо, потому что это позволяет людям не писать забавный код, но вместо этого вам нужно явно указать, какой тип события вы хотите.
// Feliz
prop.onChange (fun (e : Types.Event) -> e.Value |> ChangeGistToken |> dispatch)
// Fable.React
prop.onChange (fun e -> e.Value |> ChangeGistToken |> dispatch)
✔️ ⚠️ Экосистема Feliz в основном безопасна по типам, но не препятствует написанию неверного кода. При использовании Feliz и одного из его расширений, таких как Feliz.Bulma, вы можете легко смешивать свойства, но при этом нужно быть осторожным.
Щелкните здесь, чтобы узнать подробности
Этот код кажется нормальным с точки зрения Фелиза и компилятора F #, но он не даст ожидаемого результата.
Html.p [
text.isUppercase
text.isItalic
color.hasTextSuccess
prop.text "Hello Feliz"
]
`text.isUppsercase`,` text.isItalic` и `color.hasTextSuccess` все выводят что-то вроде` ClassName "my-css-class`. Но в React только последний будет иметь эффект, поэтому в нашем случае код будет генерировать:<p class="has-text-success">Hello Feliz<\p>
вместо того<p class="is-uppercase is-italic has-text-success>Hello Feliz</p>
Решение - использовать `++`, предложенный Feliz.Bulma:open Feliz.Bulma.Operators
Html.p [
text.isUppercase
++ text.isItalic
++ color.hasTextSuccess
prop.text "Hello Feliz"
]
Это все еще хорошая возможность, потому что это означает, что вы можете добавить поведение из другой библиотеки Feliz к «элементу Feliz», если они совместимы. Людям просто нужно быть осторожными с этим.ℹ Сначала я подумал, что Фелиз не предлагал синтаксический сахар ev.Value
который мы получаем при использовании Fable.React, но это не так.
Fable.React.Extension
содержит синтаксический сахар, поэтому мы можем просто открыть его, чтобы не загрязнять контекст всеми функциями Fable.React.
open Feliz
open Fable.React.Extensions
ℹ Синтаксис не воспроизводит мышление HTML. Feliz - это скорее синтаксический сахар поверх React API, чем HTML. Фелиз мыслит категориями свойств, потому что даже children
- это собственность.
✔️ Хорошо интегрируется с Feliz
✔️ Легче делать отступ по сравнению с Fulma
Щелкните здесь, чтобы узнать подробности
// Fulma
Card.card [ ]
[ Card.header [ Common.Props [ OnClick (fun _ -> ToggleWidget title |> dispatch ) ] ]
[ Card.Header.title [ ]
[ Icon.icon [ Icon.Props [ Style [ MarginRight ".5em" ] ] ]
[ Fa.i [ icon; Fa.Size Fa.FaLarge ] [] ]
str title ]
Card.Header.icon [ ]
[ Icon.icon [ ] [ Fa.i [ headerIcon ; Fa.Size Fa.FaLarge ] [] ] ] ]
ofOption content ]
// Feliz.Bulma
Bulma.card [
Bulma.cardHeader [
prop.onClick (fun _ -> ToggleWidget title |> dispatch )
prop.children [
Bulma.cardHeaderTitle [
Bulma.icon [
prop.style [
style.marginRight (length.em 0.5)
]
prop.children [
Fa.i [ icon; Fa.Size Fa.FaLarge ] []
]
]
Html.text title
]
Bulma.cardHeaderIcon [
Bulma.icon [
Fa.i [ headerIcon ; Fa.Size Fa.FaLarge ] []
]
]
]
]
Html.ofOption content
]
✔️ Компоненты Bulma
легко идентифицировать благодаря префиксу Bulma
✔️ ⚠️ Свойства доступны, но загрязняют контекст button.*
, help.*
, columns.*
.
Теоретически люди должны использовать только один фреймворк CSS, поэтому я не думаю, что у них возникнут конфликты из-за общих свойств, таких как button.*
, columns.*
и т. Д.
✔️ Иерархия компонентов кажется достаточно простой для понимания
Bulma.card
> Bulma.cardHeader
> Bulma.cardHeaderTitle
Нажмите здесь, например
Bulma.card [
Bulma.cardHeader [
prop.onClick (fun _ -> ToggleWidget title |> dispatch )
prop.children [
Bulma.cardHeaderTitle [
// ...
]
Bulma.cardHeaderIcon [
// ...
]
]
]
]
⚠️ Но некоторые компоненты не соответствуют одному и тому же соглашению
Bulma.passwordInput
вместо Bulma.inputPassword
В этом случае вы не сможете легко изучить различные типы входных данных, потому что они не начинаются с одного и того же «префикса».
✔️ ⚠️ Feliz.Bulma позволяет легко смешивать поведения компонентов.
Щелкните здесь, чтобы узнать подробности
Bulma.button [
// Properties specific to a button coming from Feliz.Bulma
button.isOutlined
// Properties specific to a tooltip coming from Feliz.Bulma
tooltip.hasTooltipRight
tooltip.text tooltipText
// General properties coming from Feliz
prop.disabled isCompiling
prop.onClick (fun _ -> dispatch msg)
prop.children [
Bulma.icon [
icon.isLarge
prop.children faIcon
]
]
]
Это приятно, потому что, как видите, легко добавить новое поведение к существующему компоненту. Здесь мы добавили всплывающую подсказку к кнопке. Но это также означает, что вы можете написать недопустимый код, например:Html.select [
select.isFullwidth
]
вместо тогоBulma.select [
select.isFullwidth
]
Fulma более строго относится к разделению компонентов и не позволяет вам смешивать поведение, если вы не передаете классы CSS через свойства CustomClass.✔️ ⚠️ Feliz.Bulma не позволяет контролировать, какой HTML-элемент мы хотим выводить.
Например, у нас есть только Bulma.field
который генерирует div
. Однако иногда в качестве вывода требуется элемент p
.
✔️ ⚠️ Фелиз.Бульма - точное отображение над Булмой
Это приятно, потому что он тонкий.
Но это также означает:
Например, при написании компонентов Bulma.tabs
вы не следуете инструкциям и должны знать, что tabs
нужно ul
за которым следует li
с a
в нем.
Щелкните здесь, чтобы увидеть код
// Feliz + Feliz.Bulma
Bulma.tabs [
tabs.isCentered
tabs.isMedium
tabs.isToggle
prop.children [
Html.ul [
Html.li [
if (activeTab = CodeTab.FSharp) then
prop.className "is-active"
prop.onClick (fun _ -> SetCodeTab CodeTab.FSharp |> dispatch)
prop.children [
Html.a [
prop.text "F#"
]
]
]
Html.li [
if (activeTab = CodeTab.Html) then
prop.className "is-active"
prop.onClick (fun _ -> SetCodeTab CodeTab.Html |> dispatch)
prop.children [
Html.a [
prop.text "HTML"
]
]
]
Html.li [
if (activeTab = CodeTab.Css) then
prop.className "is-active"
prop.onClick (fun _ -> SetCodeTab CodeTab.Css |> dispatch)
prop.children [
Html.a [
prop.text "CSS"
]
]
]
]
]
]
Fulma позволяет пользователю больше думать о «компонентах Bulma».// Fable.React + Fulma
Tabs.tabs [ Tabs.IsCentered
Tabs.Size Size.IsMedium
Tabs.IsToggle ]
[ Tabs.tab [ Tabs.Tab.IsActive (activeTab = CodeTab.FSharp)
Tabs.Tab.Props [
OnClick (fun _ -> SetCodeTab CodeTab.FSharp |> dispatch)
] ]
[ a [ ] [ str "F#" ] ]
Tabs.tab [ Tabs.Tab.IsActive (activeTab = CodeTab.Html)
Tabs.Tab.Props [
OnClick (fun _ -> SetCodeTab CodeTab.Html |> dispatch)
] ]
[ a [ ] [ str "HTML" ] ]
Tabs.tab [ Tabs.Tab.IsActive (activeTab = CodeTab.Css)
Tabs.Tab.Props [
OnClick (fun _ -> SetCodeTab CodeTab.Css |> dispatch)
] ]
[ a [ ] [ str "CSS" ] ] ]
Примечание:
Fulma рассматривает tab
как компонент и предлагает специальную оболочку для Tabs.Tab.*
.
Фульме все еще нужно, чтобы вы знали, что необходим элемент a
, но мы могли бы добавить его по умолчанию (это относится к некоторым компонентам).
✔️ ⚠️ Feliz.Bulma оказывает меньшее влияние на размер пакета в небольшом проекте, но будет иметь более значительное влияние при увеличении размера проекта.
Щелкните здесь, чтобы узнать подробности
Fulma использует множество DU для моделирования классов Bulma. Вы можете взглянуть на [Common.fs] (https://github.com/Fulma/Fulma/blob/2f99474cd6c793776001d07da009f7211be2f30c/src/Fulma/Common.fs); также каждый компонент имеет свои собственные DU. Для этого требуется, чтобы Fulma реализовала вызов функции parseOptions, которая, говоря простым языком, преобразует DU в классы. Feliz.Bulma использует более прямой подход, не создавая DSL поверх классов Bulma, а вместо этого напрямую выводя классы.
// Fulma
Column.column
[
Column.Width (Screen.Desktop, Column.IsHalf)
Column.Width (Screen.Mobile, Column.IsFull)
]
[
// ...
]
// Feliz
Bulma.column [
column.isHalfDesktop
column.isFullMobile
prop.children [
// ...
]
]
Благодаря прямому использованию классов и манипулированию списком свойств Feliz.Bulma не требует больших затрат на все DU и код, добавленные в Fulma. Однако для «присоединения» ко всем классам по-прежнему требуется дополнительный проход. Эта часть выполняется с помощью [модуль Feliz.Bulma.ElementBuilders.Helpers] (https://github.com/Dzoukr/Feliz.Bulma/blob/3ecbba1579d2a26281f24e6a6664b5d9c5222603/src/Feliz.BulmaLders.Element- эти функции встроены. Вот почему чем больше ваш проект, тем больше влияние на ваш код.⚠️ Добавить новую цветовую поддержку непросто.
В Feliz.Bulma каждый компонент имеет собственную реализацию цвета, например button.isWarning
, help.isWarning
и т. Д.
Итак, если вы хотите добавить свой цвет, вам нужно реализовать все button.isMyNewColor
, help.isMyNewColor
В Fulma, все они разделяют один и тот же тип цвета . См. Документацию
✔️ Следует структуре HTML, если вы думаете о ней как о списке свойств и списке дочерних элементов.
⚠️ Трудно установить правила отступов, потому что нам нужно организовать двойной список, и, как правило, мы делаем много исключительных случаев.
Нажмите здесь, чтобы получить подробное объяснение
Пример:
// When I want to put an empty div
div [ ] [ ]
// When I want to put a div with a single property
div [ ClassName "button" ] [ ]
// or
div [ ClassName "button" ]
[ ]
// When I want to put a div with several property
div [ ClassName "button"; Id "my-button" ]
[ ]
// yes but what if one of my property is not that simple?
div
[
ClassName "button"
OnClick (fun _ ->
// do something
)
]
[ ]
// It's also possible to have consistent indentation if you do something like that
div [ ] [
// Children 1
// Children 2
]
// But if you have non simple property you still have problems, I don't personally don't find it easy to read
// I am not sure if that's how people would write it because I don't use this format personally
div [
ClassName "button"
OnClick (fun _ ->
// do something
)
] [
div [ ] [
str "Children 1"
]
]
// and so on
Как вы можете видеть, имея дело с несколькими случаями в списке свойств, у нас есть несколько возможных синтаксисов. Если бы мне пришлось установить согласованный синтаксис в моем проекте, это было бы примерно так:div
[
// Property 1 ...
// Property 2 ...
// Property 3 ...
]
[
div
[
// Property 1 ...
// Property 2 ...
// Property 3 ...
]
[
// Children 1 ...
// Children 2 ...
// Children 3 ...
]
div
[
// Property 1 ...
// Property 2 ...
// Property 3 ...
]
[
// Children 1 ...
// Children 2 ...
// Children 3 ...
]
]
// So for an empty element
div
[
]
[
]
// Awesome... 🙄
Для сравнения в Фелизе я делаю:// Empty div
Html.div [ ]
// Non empty div
Htmldiv [
// Property 1
// Property 2
// Property 3
prop.children [
Html.div [
// Property 1
// Property 2
// Property 3
]
Html.div [
// Property 1
// Property 2
// Property 3
// Complexe property
OnClick (fun _ ->
// Do something
)
]
]
]
Итак, у меня сейчас только 2 случая, и я мог бы даже написать пустую версию на нескольких строках без лишнего шума, если бы мне действительно нужен был единственный способ структурирования кода Feliz.⚠️ Большая часть API не типизирована
type HTMLAttr =
| DefaultChecked of bool
| DefaultValue of obj
| Accept of string
| AcceptCharset of string
| AccessKey of string
| Action of string
| AllowFullScreen of bool
| AllowTransparency of bool
✔️ ⚠️ Некоторые части API являются типизированными, но не все, что означает, что код не согласован.
✔️ Поддерживает SSR
✔️ Типобезопасный API
Modifier.TextAlignment (Screen.All, TextAlignment.Centered)
Button.button [ Button.Color IsWhite ]
[ str "White" ]
✔️ API Fulma легко изучить с помощью intellisense, если вы понимаете, как он структурирован
✔️ Фульма заставляет задуматься о компонентах
✔️ Упростите расширение поддерживаемого цвета благодаря IsCustomColor
// All you need to add `custom-purple` support to all your components is this line
let isCustomPurple = IsCustomColor "custom-purple"
✔️ ⚠️ Я думаю, что у него хорошая документация с примерами для всех компонентов, но не каждый компонент содержит одинаковый уровень информации
✔️ ⚠️ Влияние Фульмы на размер вашего бандла «стабильное». Этот момент был описан в разделе Фелиз.Бульма.
⚠️ Людям нелегко найти «Особых помощников».
⚠️ Код Fulma добавляет шума в ваш код из-за строго типизированного DSL
Щелкните здесь, чтобы увидеть пример
// Fulma
Heading.p [ Heading.IsSubtitle
Heading.Is5
Heading.Modifiers [ Modifier.TextAlignment (Screen.All, TextAlignment.Centered) ] ]
[ str "is only available on desktop" ]
// Feliz.Bulma
Bulma.subtitle5 [
text.hasTextCentered
prop.text "is only available on desktop"
]
⚠️ Код Fulma не так просто правильно отформатировать, потому что он имеет много вложенных списков при объединении Props
, Modifiers
Я работал над этим анализом в течение 2-3 недель и все еще могу продолжить. Но я должен положить этому конец, потому что на это уходит много времени, и я думаю, что теперь я лучше понимаю ситуацию.
Все это говорит о том, что можно было бы перечислить больше хороших моментов или проблем, особенно в отношении Fable.React и Fulma, но это также самая сложная часть для меня. Я использую их и проектирую более 3 лет, поэтому трудно иметь на них объективное представление.
Конвертировать из Fable.React в Feliz было достаточно просто. Feliz совместим с Fable. React вы можете выполнять преобразование в прогрессивном режиме: файл на файл, компонент на компонент и т. Д.
Чтобы быть уверенным, что я преобразовал все, я удалил все инструкции open Fable.React
и open Fable.React.Props
. Я также удалил Fulma как зависимость.
Конечно, я забыл некоторые файлы, поэтому исправил ошибки компилятора, и все заработало.
Вы можете увидеть запрос слияния хостинг преобразования здесь .
Поначалу открывая для себя Feliz, я защищался, потому что он не следовал «пути HTML / JSX», и это альтернативный проект для вещей, в которые я вложил много усилий.
Затем я вспомнил, как работают инновации и что позволяет нам расти. Например, благодаря тому, что сегодня у нас есть Эльмиш.
Еще я вспомнил, что JSX - это не «настоящий React API», действительно, React API - это React.createElement
. JSX - это синтаксический сахар поверх него, то же самое касается Fable.React и Feliz. Я настаиваю на этом, потому что для меня это помогло мне двигаться вперед и интересоваться этим.
Чтобы протестировать Фелиза, я решил использовать проект среднего размера - Fable REPL. Fable REPL - не сложное приложение, но оно использует множество функций Fable и React.
Неполный список вещей, которые я протестировал благодаря этому решению:
Когда я начал конвертацию, я был очень доволен тем, насколько легко было отформатировать код. Я думаю, что условию написания представления, основанного на Фелизе, было бы очень легко следовать. Чем больше растут мои приложения, тем больше я считаю важным форматирование кода.
Затем в середине я начал что-то раздражать, но не мог найти что.
Я закончил конвертировать Fable REPL в Feliz и не был уверен, нравится ли мне мой опыт работы с ним.
Только сейчас я пытаюсь завершить свой анализ и понимаю, что меня сдерживает. Это не столько связано с Фелиз, сколько с Фелиз.Бульма.
Важно помнить, что более 2,5 лет я работаю над Fulma и улучшаю ее. Fulma - один из моих самых больших проектов. Писать код с его помощью - это здорово, особенно потому, что все типизировано и заставляет думать в терминах компонентов.
Фелиз.Бульма придерживается другого подхода и моложе Фульмы; ему всего 5 месяцев.
С учетом всего сказанного, я думаю , что настало время перейти к моему выводу :)
Я считаю, что самым большим преимуществом Фелиза является стиль единого списка. Об этом я много говорил, но для меня возможность легко форматировать свой код и не думать, с чего начать следующую строку, является большим плюсом.
Во-вторых, необходимо иметь типобезопасный API. Он более подробный, чем эквивалент CSS, но я думаю, что это хорошая функция. Я не делал с ним ничего особенного, поэтому не могу сказать, все ли поддерживается, но если это не так, мы всегда можем сделать пиар, чтобы это исправить :).
Feliz.Bulma показывает многообещающий способ расширения Feliz, но еще не достаточно зрел, чтобы быть прямым эквивалентом Fulma. Это то, что я хочу изучить с помощью @Dzoukr, и я надеюсь, что мы сможем найти золотую середину между простотой Feliz.Bulma и полнотой, но многословием Fulma.
3 года назад, 8 марта 2017 года , Томас, Евгений и я решили объединить Fable.Arch с Эльмишем. Это позволило нам как сообществу построить потрясающую экосистему, которая есть у нас сегодня.
Я думаю, что сейчас мы живем в похожий период с Feliz и Fable.React. Я думаю, что Фелиз получит больше поддержки, чем Fable.
но оба будут сосуществовать вместе. В конце концов, они оба хорошо работают вместе, это означает, что люди могут выбрать тот, который им больше нравится.
Спасибо, что прочитали мой анализ, и я буду рад обсудить его с вами в разделе комментариев :)
Отличный анализ.
Лично для меня, даже несмотря на то, что форматирование двойного списка иногда является проблемой, я чувствую, что глядя на код Fable.React, я лучше вижу структуру нижележащего html. Это div [.., а не Html.div [.... (и т. Д.). Это не так уж важно, но моему мозгу, кажется, легче разобрать Fable.React.
Отличное написание @MangelMaxime , вы сделали много хороших
Из того, что я собрал, главный вывод - это в основном проблемы с тем, как расширяется библиотека, и проблемы, которые возникают, когда они не выполняются оптимально.
Я могу определенно согласиться с тем, что написание библиотек для Feliz
возлагает гораздо больше усилий на разработчика, но, на мой взгляд, это стоит усилий, когда полученный api так приятно использовать.
Я написал изрядное количество расширений для Feliz
поэтому я думаю, что могу дать некоторое представление о том, как смягчить многие из этих проблем:
Я использую Visual Studio, и у меня нет проблем с поиском доступных мне перегрузок, может быть, это что-то, что можно улучшить с помощью ионидов?
Мы могли бы просто сделать prop.text
единственной встроенной функцией, которая требует члена toString
и принимает любой тип?
Вместо того:
[<Erase>]
type editor =
/// <summary>Triggered when the Editor has been mounted</summary>
static member inline editorDidMount (f : System.Func<Monaco.Editor.IStandaloneCodeEditor, Monaco.IExports, unit>) = Interop.mkAttr "editorDidMount" f
Напишите:
[<Erase>]
type editor =
/// <summary>Triggered when the Editor has been mounted</summary>
static member inline editorDidMount (f : Monaco.Editor.IStandaloneCodeEditor -> Monaco.IExports -> unit) = Interop.mkAttr "editorDidMount" (Func<_,_,_> f)
Затем вы можете вызвать свойство, как вы ожидаете, на стороне клиента.
Я не видел, чтобы кто-то еще применял это в той степени, в какой я применяю в некоторых из моих библиотек, и может быть не совсем применим при расширении Html
. Чтобы предотвратить это, вы добавите дополнительные типы интерфейса к определяемым вами свойствам, в моей самой большой Feliz
library Feliz.Plotly
Я настроил ее таким образом, что вы получите ошибку компилятора, если вы попробуйте использовать недействительное свойство. Единственный недостаток - это довольно большая работа для разработчика библиотеки.
Нажмите, чтобы развернуть
[<AutoOpen;EditorBrowsable(EditorBrowsableState.Never)>]
module Types =
type IPlotProperty = interface end
type IModeBarButtonsProperty = interface end
type IAaxisProperty = interface end
type IAggregateProperty = interface end
type IAggregationProperty = interface end
type IAggregationsProperty = interface end
type IAngularaxisProperty = interface end
type IAnimationProperty = interface end
type IAnnotationProperty = interface end
type IAnnotationsProperty = interface end
type IAreaProperty = interface end
type IAspectratioProperty = interface end
type IAxisProperty = interface end
type IBarProperty = interface end
type IBarpolarProperty = interface end
type IBaxisProperty = interface end
type IBorderProperty = interface end
type IBoxProperty = interface end
type IButtonProperty = interface end
type ICameraProperty = interface end
type ICandlestickProperty = interface end
type ICapsProperty = interface end
type ICarpetProperty = interface end
type ICaxisProperty = interface end
type ICellsProperty = interface end
type ICenterProperty = interface end
type IChoroplethProperty = interface end
type IChoroplethmapboxProperty = interface end
type ICircleProperty = interface end
type IColoraxisProperty = interface end
type IColorbarProperty = interface end
type IColorscaleProperty = interface end
type IColorscalesProperty = interface end
type IConcentrationscalesProperty = interface end
type IConeProperty = interface end
type IConfigProperty = interface end
type IConnectorProperty = interface end
type IContourProperty = interface end
type IContourcarpetProperty = interface end
type IContoursProperty = interface end
type ICumulativeProperty = interface end
type ICurrentvalueProperty = interface end
type IDecreasingProperty = interface end
type IDeltaProperty = interface end
type IDensitymapboxProperty = interface end
type IDiagonalProperty = interface end
type IDimensionProperty = interface end
type IDimensionsProperty = interface end
type IDomainProperty = interface end
type IEditsProperty = interface end
type IErrorXProperty = interface end
type IErrorYProperty = interface end
type IErrorZProperty = interface end
type IEyeProperty = interface end
type IFillProperty = interface end
type IFilterProperty = interface end
type IFontProperty = interface end
type IFrameProperty = interface end
type IFramesEntryProperty = interface end
type IFramesProperty = interface end
type IFunnelProperty = interface end
type IFunnelareaProperty = interface end
type IGaugeProperty = interface end
type IGeoProperty = interface end
type IGradientProperty = interface end
type IGridProperty = interface end
type IGroupbyProperty = interface end
type IHeaderProperty = interface end
type IHeatmapProperty = interface end
type IHeatmapglProperty = interface end
type IHistogram2dProperty = interface end
type IHistogram2dcontourProperty = interface end
type IHistogramProperty = interface end
type IHoverlabelProperty = interface end
type IImageProperty = interface end
type IImagesProperty = interface end
type IIncreasingProperty = interface end
type IIndicatorProperty = interface end
type IInsidetextfontProperty = interface end
type IIsosurfaceProperty = interface end
type ILabelfontProperty = interface end
type ILataxisProperty = interface end
type ILayerProperty = interface end
type ILayersProperty = interface end
type ILayoutProperty = interface end
type ILeafProperty = interface end
type ILegendProperty = interface end
type ILightingProperty = interface end
type ILightpositionProperty = interface end
type ILineProperty = interface end
type ILinkProperty = interface end
type ILonaxisProperty = interface end
type IMapboxProperty = interface end
type IMarginProperty = interface end
type IMarkerProperty = interface end
type IMeanlineProperty = interface end
type IMesh3dProperty = interface end
type IModebarProperty = interface end
type INodeProperty = interface end
type INumberProperty = interface end
type IOhlcProperty = interface end
type IOutsidetextfontProperty = interface end
type IPadProperty = interface end
type IParcatsProperty = interface end
type IParcoordsProperty = interface end
type IPathbarProperty = interface end
type IPieProperty = interface end
type IPointcloudProperty = interface end
type IPolarProperty = interface end
type IProjectProperty = interface end
type IProjectionProperty = interface end
type IRadialaxisProperty = interface end
type IRangebreakProperty = interface end
type IRangebreaksProperty = interface end
type IRangefontProperty = interface end
type IRangeselectorProperty = interface end
type IRangesliderProperty = interface end
type IRotationProperty = interface end
type ISankeyProperty = interface end
type IScatter3dProperty = interface end
type IScatterProperty = interface end
type IScattercarpetProperty = interface end
type IScattergeoProperty = interface end
type IScatterglProperty = interface end
type IScattermapboxProperty = interface end
type IScatterpolarProperty = interface end
type IScatterpolarglProperty = interface end
type IScatterternaryProperty = interface end
type ISceneProperty = interface end
type ISelectedProperty = interface end
type IShapeProperty = interface end
type IShapesProperty = interface end
type ISlicesProperty = interface end
type ISliderProperty = interface end
type ISlidersProperty = interface end
type ISortProperty = interface end
type ISpaceframeProperty = interface end
type ISplomProperty = interface end
type IStartsProperty = interface end
type IStepProperty = interface end
type IStepsProperty = interface end
type IStreamProperty = interface end
type IStreamtubeProperty = interface end
type IStyleProperty = interface end
type IStylesProperty = interface end
type ISunburstProperty = interface end
type ISurfaceProperty = interface end
type ISymbolProperty = interface end
type ITableProperty = interface end
type ITernaryProperty = interface end
type ITextfontProperty = interface end
type IThresholdProperty = interface end
type ITickfontProperty = interface end
type ITickformatstopProperty = interface end
type ITickformatstopsProperty = interface end
type ITilingProperty = interface end
type ITitleProperty = interface end
type ITotalsProperty = interface end
type ITracesProperty = interface end
type ITransformsProperty = interface end
type ITransitionProperty = interface end
type ITreemapProperty = interface end
type IUniformtextProperty = interface end
type IUnselectedProperty = interface end
type IUpProperty = interface end
type IUpdatemenuProperty = interface end
type IUpdatemenusProperty = interface end
type IViolinProperty = interface end
type IVolumeProperty = interface end
type IWaterfallProperty = interface end
type IXProperty = interface end
type IXaxisProperty = interface end
type IXbinsProperty = interface end
type IYProperty = interface end
type IYaxisProperty = interface end
type IYbinsProperty = interface end
type IZProperty = interface end
type IZaxisProperty = interface end
type IButtonsProperty = inherit IModeBarButtonsProperty
type IMeasureProperty = interface end
type ITemplateProperty = interface end
Точно так же вы можете реализовать в коде библиотеки что-то, чтобы «автоматически» комбинировать свойства, если хотите. Я не уверен, как это работает при использовании вещей за пределами вашей собственной библиотеки. Уловка заключается в том, чтобы сделать эти предметы другим типом, а не просто IReactProperty
. Например, в Feliz.Plotly
я делаю много вещей, где в зависимости от заданных конфигураций я изменяю / собираю / изменяю вводимые пользователем данные, чтобы должным образом преобразовать их в то, как должен выглядеть реальный код. В некоторых отношениях он действительно хорош для удаления вещей, которые всегда присутствуют.
Я думаю, что большую часть боли, которую вы испытывали, можно было бы решить с помощью более качественной документации о том, как ориентироваться при написании ваших собственных библиотек способом "Feliz". Может быть, мы с @ Zaid-Ajaj поработаем над этим в будущем.
Спасибо @ l3m
Лично для меня, даже несмотря на то, что форматирование двойного списка иногда является проблемой, я чувствую, что глядя на код Fable.React, я лучше вижу структуру нижележащего html. Это div [.., а не Html.div [.... (и т. Д.). Это не так уж важно, но моему мозгу, кажется, легче разобрать Fable.React.
Действительно, переключить способ чтения кода непросто, и поэтому я упомянул, что мы не должны рассматривать его как HTML, в моем случае это помогло мне переключиться.
Я полагаю, что с F # 5 и возможностью «открывать статические классы» Фелиз сможет поддерживать синтаксис Html.div
и div
зависимости от того, открываете ли вы класс Html или нет.
Спасибо @Shmew за комментарий, да и вообще я забыл, что есть несколько типов «библиотек» для Feliz.
По поводу «Написание неверного кода» да, но в некоторых библиотеках мы действительно хотим «расширить» тип IReactProperty
, чтобы избежать ситуации Fulma, когда вам нужно передать стандартные свойства через специальный помощник, например Props
. Причина в том, что «компоненты» Bulma - это просто специализация над элементами DOM.
Это просто код, который по умолчанию внедряет класс в элемент HTML.
Bulma.button
генерирует <div class="button">
В случае библиотеки, которая работает с «настоящими» компонентами (извините, не знаю, как назвать ее по-другому), ваше решение действительно правильное. Например, это подход, используемый Fable.ReactLeaflet, где я определяю конкретные свойства для каждого компонента. Таким образом, компоненты не обязательно должны поддерживать все стандартные свойства HTML.
По поводу вашего решения для "Обратных вызовов" не у меня не сработало. Но функция, переданная Fable, имела каррированные аргументы, и, если я не хотел писать что-то вроде myFunction(arg1)(arg2)
мне приходилось форсировать необработанную версию через System.Func
.
Если вы знаете, как заставить его работать, я буду рад увидеть PR, направленный на его исправление в https://github.com/fable-compiler/repl/pull/108/files.
Привет @MangelMaxime!
Прежде всего, я хочу поблагодарить вас за то, что вы потратили время и силы не только на то, чтобы опробовать Feliz на проекте, но и на написание такого обширного анализа. Я уверен, что многие пользователи Fable найдут его очень полезным и информативным.
Я очень ценю такую обратную связь и открытость и считаю, что это крайне важно для того, чтобы сделать эту библиотеку наилучшей, какой она может быть вместе с ее экосистемой: молитесь:
Я расскажу о Feliz.Bulma чуть позже, потому что я считаю, что это особенное место в экосистеме. Сначала я отвечу на некоторые проблемы, которые у вас есть, которые уже можно исправить без изменений в библиотеке.
onChange
вам нужно явно указать, какой тип события вы хотите.
На самом деле нет. Тип должен быть выведен из вашего типа сообщения следующим образом:
prop.onChange (ChangeGistToken >> dispatch)
В зависимости от типа ChangeGistToken
будет выведена правильная перегрузка. Когда случай DU равен ChangeGistToken of string
тогда будет выбрана перегрузка string -> unit
. Но это также может быть FileSelected of File
когда тип ввода file
в этом случае будет выведена перегрузка File -> unit
и так далее и тому подобное. Вам не нужен синтаксический сахар ev.Value
от Fable.React
prop.onCheckedChange будет удален, поскольку
onChange
обрабатывает логический регистр
@Shmew уже затронул эту проблему, и это действительно способ решить эти типы свойств. Важно понимать, что при реализации расширений Feliz вы можете выполнять преобразования перед установкой свойства:
type myExtension =
static member inline extenstionProperty value =
// transform value here
let transformedValue = doWeirdStuffWith value
Interop.mkAttr "extenstionProperty" transformedValue
Следуя этой логике, вы можете внутренне преобразовать 'A -> 'B -> unit
в Func<'A, 'B, unit>
:
[<Erase>]
type editor =
/// <summary>Triggered when the Editor has been mounted</summary>
static member inline editorDidMount (f : Monaco.Editor.IStandaloneCodeEditor -> Monaco.IExports -> unit) =
let transformedFunction = System.Func<Monaco.Editor.IStandaloneCodeEditor, Monaco.IExports, unit>(fun editor exported -> f editor exported)
Interop.mkAttr "editorDidMount" transformedFunction
Это более явная версия, чем та, которая предоставляется @Shmew (как вы знаете, с привязками, вам всегда нужно немного поиграть с ними, чтобы получить их правильно). Рабочий пример этого здесь
Как упоминалось выше @Shmew : правильное расширение Feliz не позволяет вам писать код, который ведет себя неправильно, а ограничение типов свойств позволяет вам реализовать это. Вы можете либо создать свойства, которые возвращают IReactProperty
например Feliz.Recharts, что обеспечивает обратную совместимость с существующими свойствами в prop
либо вы можете реализовать более специализированный тип ISpecialiedProperty
для поддержки только подмножество свойств при дублировании имен некоторых свойств из IReactProperty
для обеспечения обратной совместимости:
type felizExtension =
static member inline specializedProp (value: string) : ISpecializedProperty = unbox (prop.text value)
Это то, что я делал с Feliz.AntDesign, например здесь, где я дублирую некоторые свойства, чтобы сделать их доступными из точки входа button
(позже я мог бы сделать свойства более специализированными с помощью строгих типов, но сначала , обратная совместимость - это то, с чего вы впервые начинаете). Я считаю, что Feliz.MaterialUI делает аналогичные вещи для расширения IReactProperty
а не для специализации свойств. Это подводит нас к делу Фелиз.Бульма.
До того, как был реализован Feliz.Bulma, я думал, что нет необходимости создавать расширения Feliz для фреймворков, содержащих только CSS. Feliz позволяет очень легко составлять несколько имен классов и работать с ними по условию. Теперь с неявным yield
в F # стало еще проще. Объедините это с TypedCssClasses, и вы
Однако после того, как я увидел реализацию Feliz.Bulma от @Dzoukr, это Bulma.button
, Bulma.card
и т. Д. Их действительно приятно использовать. Что касается модификаторов, я думаю, что подход Романа легко использовать, но, как вы сказали, иногда он может давать интересные результаты. Конечно, в этом отделе есть еще что улучшить, и в любом случае я думаю, что Роман проделал огромную работу, следуя видению Фелиза, создав что-то легкое для изучения и использования.
Я просто хочу указать на огромную разницу в текущих Fable.React
и Feliz
: в управлении версиями пакетов. Версии Feliz все ее экосистемы библиотек Фемто -Совместимы , которые снимают нагрузку от пользователей , чтобы вручную установить необходимые пакеты НПХ или знать , какую версию они совместимы с. Это не похоже на многие, если не на все производные библиотеки Fable.React
и даже на сам Fable.React
, где это не так.
На самом деле нет. Тип должен быть выведен из вашего типа сообщения следующим образом:
prop.onChange (ChangeGistToken >> dispatch)
Действительно, я не думал об этом использовании.
Обратные вызовы с несколькими аргументами
@Shmew уже затронул эту проблему, и это действительно способ решить эти типы свойств.
Извините, я не видел конца фрагмента, предоставленного @Shmew. Я только что увидел подпись под декларацией и подумал, что нет, не работает.
Вы оба правы, мы можем выполнить преобразование перед передачей значения свойству.
Да, TypedCssClasses в порядке, но по сравнению с Fulma или Feliz.Bulma он не может обеспечить такой же уровень функций. Потому что не все содержится в файле CSS.
Другое дело, что в режиме разработки у нас не всегда создается файл на диске, и я не уверен, поддерживает ли TypedCssClasses этот сценарий.
Я думаю, что Роман проделал огромную работу, следуя видению Фелиза, создав нечто легкое в освоении и использовании.
Я согласен, я просто думаю, что нам нужно добавить немного работы, проделанной в Fulma, чтобы сделать ее похожей. Как я уже сказал, нам нужно найти золотую середину между ними обоими.
Недостающие функции, которые я сейчас имею в виду, позволяют управлять элементом вывода и упрощают расширение набора поддерживаемых цветов. Я не думаю, что это добавит к этому много сложностей.
@ Zaid-Ajaj благодарим вас за отзывы и особенно за то, что указали мне правильное направление использования потенциала Фелиза.
Признаюсь, я действительно не читал документацию Feliz (это плохо, я знаю), так что, возможно, они задокументированы в ней. Если нет, думаю, мы знаем еще кое-что, что нужно добавить :)
Спасибо @MangelMaxime - отличное сравнение. Вы нигде не упомянули Fantomas по поводу автоматического форматирования кода - у вас была возможность поработать с Fantomas с Fable.React или Feliz?
В одном из моих проектов Fable, где я использую Fantomas, я включил автоматическое форматирование при сохранении файлов в Ionide и должен сказать, что это действительно повышение производительности - не нужно вообще беспокоиться о ручном форматировании!
Я действительно думаю, что сейчас Fantomas набирает обороты и хотел бы увидеть его более широкое распространение, в том числе вместе с Fable и React / Feliz.
@theimowski Я не использовал Фантомас несколько раз.
В основном потому, что это мешало моему коду и затрудняло его чтение. По моему опыту, не очень хорошо играл с Fable.React и Feliz.
Мне также не нравится значение Fantomas по умолчанию, мне нужно проверить его снова в будущем, когда я узнаю, как я хочу, чтобы мой код был отступом. Но, судя по тому, что я посмотрел на репо, я не думаю, что он будет соответствовать моим потребностям в основном из-за того, что Fantomas форматирует код в зависимости от размера контекста.
Например, если я напишу что-то подобное:
type Test =
{
Prop1 : string
}
Я действительно хочу, чтобы он оставался таким, а не превращался в type Test = { Prop1 : string }
только потому, что он может уместиться в одной строке.
Возможно, запись - не лучший пример, но я надеюсь, вы понимаете, о чем я :)
@theimowski , приятно слышать, я использую фантомы в своих проектах, не относящихся к Fable. Придется дать ему еще один шанс и посмотреть, как он с этим справится.
@MangelMaxime благодарит за вашу работу. Каким-то образом ваш проект Fulma напал на меня в сказочный мир. И мне очень нравится путешествие.
Мне также нравится единый список, но мне также нравится DU, чем переопределение членов классов. Иногда мне интересно, поддерживает ли DU переопределение, тогда было бы здорово.
Поскольку я уже много использую Fable.React, но все же хочу единый список, я создал оператор> и могу использовать его как:
let myView =
div </> [
Classes [ ""; ""; "" ]
Children [
...
]
]
Оператор довольно прост и также использует преимущества DU, вы можете проверить мою примерную реализацию здесь: https://github.com/albertwoo/Fun.LightForm/blob/master/src/Fun.LightForm.Fable/Fable.React. Extra.fs
@ Zaid-Ajaj Спасибо и за вашу отличную работу, я также начал преобразовывать некоторые из моих проектов в Feliz и Feliz.Material.
Спасибо!
Привет @MangelMaxime!
прежде всего спасибо! Честно говоря, я не ожидал, что кто-то так глубоко изучит библиотеку, которую я создал в основном для поддержки собственных проектов и опубликовал как побочный эффект. Забавно, как раздулась первоначальная мысль «эй, как @Zaid-Ajaj разработал Фелиза - давайте сделаем то же самое для Бульмы».
Я уже создал новую проблему в репозитории Feliz.Bulma
и люблю обсуждать, как сделать версию 2 еще лучше. Похоже, у нас есть согласие по большинству вопросов, поэтому запустить ветку version2
не должно быть проблем. Также может быть полезно посмотреть, каковы планы Зейда на следующий крупный выпуск, чтобы API между последними основными версиями был на 100% совместимым.
В любом случае, еще раз спасибо - отличный анализ!
В риске возобновление старых дискуссий (! Извините) Я просто хотел бы добавить свои два цента на дискуссии отступа - это (более или менее) стилизации мы следуем , который действительно позволяют хорошему, в соответствии identation и следующая за Fable.React стиль.
Однако единственное место, к которому это не относится, - это нетривиальный стиль. Однако, по нашему опыту, это лишь небольшая часть элементов (возможно, 10-20%).
div [ ] [
Hero.hero [ Hero.IsFullHeight ] [
Hero.body [ ] [
Container.container [ ] [
img [ Src "img/fable-ionide.png"
Style [ Display DisplayOptions.Block
Width "auto"
Margin "auto" ]
]
br [ ]
Heading.h3 [ Heading.Modifiers [ Modifier.TextAlignment (Screen.All, TextAlignment.Centered) ] ] [
str "Fable REPL"
]
Heading.p [ Heading.IsSubtitle
Heading.Is5
Heading.Modifiers [ Modifier.TextAlignment (Screen.All, TextAlignment.Centered) ] ] [
str "is only available on desktop"
]
]
]
]
]
Кроме того, если вы используете VS Code и что-то вроде Rainbow Brackets, это действительно может помочь избежать перегрузки скобок.
Еще кое-что, что следует учитывать (возможно, я пропустил это выше), это то, что GiraffeViewEngine использует стиль Fable.React, то есть элемент attr-list children-list, так что просто над чем подумать с точки зрения людей, переходящих между ними.
@ Zaid-Ajaj хорошо отзывается о Фемто; есть ли причина, по которой это не может быть реализовано компонентами стиля Fable.React, или есть что-то присущее стилю Feliz, с которым связан Femto?
есть ли причина, по которой это не может быть реализовано компонентами стиля Fable.React, или есть что-то присущее стилю Feliz, с которым связан Femto?
@isaacabraham
Библиотеки, производные от Fable.React, могут (и должны) добавлять метаданные Femto, но сам Fable.React не может, потому что он содержит несовместимое сочетание react
, react-dom
и react-native
. @MangelMaxime начал некоторую работу по разделению пакетов, но это было намного больше, чем ожидалось, и, вероятно, внесет критические изменения.
Для библиотек, производных от Fable.React
означает, что они должны включать не только метаданные npm своих зависимостей, но также включать совместимые версии react
и react-dom
потому что Fable.React этого не делает. не делайте этого для них (в отличие от Feliz, который начинается с react
и react-dom
так что расширения Feliz добавляют только то, что им нужно). К сожалению, я еще не видел, чтобы какая-либо из этих библиотек проявила инициативу по улучшению ситуации, даже если решение существует уже довольно давно.
Что касается форматирования: Fantomas еще не может разумно форматировать DSL и требует некоторой работы по настройке форматирования списка или имеет какой-то флаг «Feliz-mode» для форматирования React DSL с использованием хороших значений по умолчанию (которые мы должны придти вверх с)
@ Zaid-Ajaj Проблема с зависимостями React npm также более сложна, поскольку должна быть возможность использовать preact вместо реакции, не нарушая Femto.
@ l3m Действительно, но в этом случае мы могли бы сделать дополнение к Femto для поддержки этого случая. Он кое-что меня помнит, так что, возможно, у нас есть проблема с этим в репозитории Femto (извините, у меня нет времени проверить прямо сейчас ^^)
@ l3m Preact можно использовать вместо React независимо от метаданных Femto npm, потому что вам нужно только настроить псевдонимы импорта модулей в соответствии с рекомендациями в Переход на Preact, когда у вас есть существующее приложение React.
Создание чистой привязки Preact (100% не-React-код) не является целью Feliz и, вероятно, должно быть реализовано как отдельная библиотека (Feliz.Preact, которая не зависит от Feliz), из которой будут расширены привязки только для Preact и используется, если вы хотите держаться подальше от preact/compat
@ Zaid-Ajaj Я использую preact прямо сейчас в своем приложении Elmish, и он работает хорошо. Я просто опасался, что Фемто изменит packages.json, если увидит nuget с зависимостями React, и я хотел это выделить. Если это не проблема, тем лучше.
Кроме того, preact/compat
больше не требуется с последней версией preact, теперь она находится в ядре.
Рискуя возобновить старые дискуссии (извините!) Я просто хотел добавить свои два цента к дебатам об отступах - это (более или менее) стиль, которому мы следуем, и который _ позволяет_ обеспечить красивую, последовательную идентификацию и отслеживание для Fable.React стиль.
Я делаю отступы в коде, очень похожем на код Исаака, и он довольно удобочитаем.
Я знаю, что его сложно сравнивать с одним списком, но отступ в исходном посте может отражать что-то похожее на его код, чтобы лучше сравнить.
Я полагаю, что с F # 5 и возможностью «открывать статические классы» Фелиз сможет поддерживать синтаксис
Html.div
иdiv
зависимости от того, открываете ли вы класс Html или нет.
Это было бы супер круто. Можно ли сделать класс Html статическим, чтобы его можно было открывать?
@ fc1943s Html
, prop
и style
- все статические классы. Однако я не рекомендую открывать их, когда функция становится доступной в F # 5, потому что все дело в группировке и точке входа для обнаружения доступных функций в этом статическом классе.
Как открытие статического класса может помешать обнаружению? Вы все равно можете набрать Feliz.Html.
@MaxWilsonMS Это потребовало дополнительных шагов для вывода «окончательного» кода.
И вы должны написать Feliz.Html.div
а затем стереть часть Feliz.Html.
которая кажется странной.
Что хорошо, так это то, что люди могут выбирать, открывать статический класс или нет, в зависимости от своих предпочтений. :)
Не уверен, насколько это будет полезно, поскольку я повторяю то, что было сказано выше, но ощущаю себя полным новичком:
Я предпочитаю подход Фелиза для вдавливания. Я пробовал подходы, аналогичные тому, что предлагал Исаак, но поскольку отступы - это не все 2/4, «я иногда трачу время на размышления об этом». С Фелиз я вообще не думаю об этом.
Если бы я делал нестандартный элемент, я бы сейчас делал это способом Fable.React. Я взглянул на постройку вещей «по-Фелизски» и тут же убежал (в какой-то момент я еще вернусь!).
Было бы очень полезно, если бы в документации более регулярно уделялось приоритетное внимание аспекту «вот как сделать настраиваемое свойство». Я думаю, будет справедливо согласиться с тем, что, имея всего несколько авторов, эти библиотеки часто будут изо всех сил пытаться предложить поверхность API для всего, что возможно в CSS (например), поэтому, если новичок застрянет, когда они не могут установить "fontSize" в «em», или не могут найти «grid-template-rows», или понятия не имеют, что они должны предоставить аргумент «Screen.All» - было бы хорошо, если бы они знали, как это обойти.
Я думаю, что можно было бы внести некоторые улучшения в "Качество жизни", которые позволили бы избавиться от некоторых потенциальных проблем ... например, когда я смотрю на длинные вертикальные списки стилей в Feliz, я начинаю задаваться вопросом, может ли быть style.paddingHorizontal
и style.paddingVertical
. Я понимаю, что могу создавать своих собственных помощников, но здесь не место для запросов функций, и что может быть желание избежать введения нестандартных вещей :)
Мне нравится идея открыть статический класс Html
в новом F #. Важно то, что мои коллеги смогут понять это, когда посмотрят мне через плечо, и я думаю, что важно привлечь больше людей. Чтобы сыграть в адвоката дьявола: div
не займет много времени, и если мне нужно это открыть, то это наименьшая из проблем, с которыми я столкнусь при использовании установки, которая творит магию, пока скрывая от меня Javascript, React, CSS и т. д. и т. д. Тем не менее, в целом API-интерфейс легко обнаруживается.
В частности, для переходов / анимации в стилях способ Feliz имеет большой смысл - с ним действительно приятно работать.
В более общем плане и, вероятно, косвенно: проблема, с которой я постоянно сталкиваюсь, заключается в том, чтобы понять, где заканчивается мир Elmish и начинается мир React. На самом деле это не проблема ни одной из библиотек, но поскольку я не имею ни малейшего представления о чем-либо React, меня смущает тот факт, что я могу получить функциональный компонент от Fable.React или Feliz. Конечно, я обязан научиться этому, но я подумал, что об этом стоит упомянуть. В настоящее время я смешиваю подходы Elmish и React, и я считаю, что это приводит к повторному рендерингу всех компонентов при обновлении, но я не знаю «правильного» способа сделать что-то, чтобы этого избежать, потому что примеры полностью построенных приложений, подобных этому: трудно найти. Иногда у меня складывается впечатление, что я должен сначала научиться создавать производственные приложения React на Javascript, а затем перейти на Fable / Elmish, но это кажется довольно серьезным барьером для входа. Отказ от ответственности: я не читал подробно документацию Feliz, и это действительно хорошо - так что это, вероятно, на мне!
Спасибо всем за то, что поделились этими библиотеками!
Спасибо за ваш вклад @ drk-mtr!
Если бы я делал нестандартный элемент, я бы сейчас делал это способом Fable.React. Я взглянул на постройку вещей «по-Фелизски» и тут же убежал (в какой-то момент я еще вернусь!).
Да, поначалу это может показаться довольно пугающим, но, когда вы привыкнете, это довольно просто. При этом для разработчика это небольшая начальная стоимость при написании библиотек. Я считаю это довольно приемлемым компромиссом, поскольку подавляющее большинство пользователей не собираются писать библиотеки. К счастью, сама работа довольно проста, и некоторое копирование + вставка может ускорить большую часть работы (или, как некоторые из нас, написание генераторов для создания кода для нас).
Было бы очень полезно, если бы в документации более регулярно уделялось приоритетное внимание аспекту «вот как сделать настраиваемое свойство». Я думаю, будет справедливо согласиться с тем, что, имея всего несколько авторов, эти библиотеки часто будут изо всех сил пытаться предложить поверхность API для всего, что возможно в CSS (например), поэтому, если новичок застрянет, когда они не могут установить "fontSize" в «em», или не могут найти «grid-template-rows», или понятия не имеют, что они должны предоставить аргумент «Screen.All» - было бы хорошо, если бы они знали, как это обойти.
На всякий случай, если вы не в курсе (я не мог точно сказать из этого контекста):
Существует метод custom
style
типов prop
и style
.
Все, что принимает ICssUnit
может быть установлено как: style.fontSize (length.em 1)
Обновление документов должно быть достаточно простым.
Я думаю, что можно было бы внести некоторые улучшения в "Качество жизни", которые позволили бы избавиться от некоторых потенциальных проблем ... например, когда я смотрю на длинные вертикальные списки атрибутов стиля в Feliz, я начинаю задаваться вопросом, могут ли быть style.paddingHorizontal и style.paddingВертикальный. Я понимаю, что могу создавать своих собственных помощников, но здесь не место для запросов функций, и что может быть желание избежать введения нестандартных вещей :)
В моей книге определенно приветствуется все, что помогает облегчить взаимодействие с пользователем. Я бы хотел увидеть проблему / PR по любой из этих замеченных вами вещей!
В более общем плане и, вероятно, косвенно: проблема, с которой я постоянно сталкиваюсь, заключается в том, чтобы понять, где заканчивается мир Elmish и начинается мир React. На самом деле это не проблема ни одной из библиотек, но поскольку я не имею ни малейшего представления о чем-либо React, меня смущает тот факт, что я могу получить функциональный компонент от Fable.React или Feliz. Конечно, я обязан научиться этому, но я подумал, что об этом стоит упомянуть. В настоящее время я смешиваю подходы Elmish и React, и я считаю, что это приводит к повторному рендерингу всех компонентов при обновлении, но я не знаю «правильного» способа сделать что-то, чтобы этого избежать, потому что примеры полностью построенных приложений, подобных этому: трудно найти. Иногда у меня складывается впечатление, что я должен сначала научиться создавать производственные приложения React на Javascript, а затем перейти на Fable / Elmish, но это кажется довольно серьезным барьером для входа. Отказ от ответственности: я не читал подробно документацию Feliz, и это действительно хорошо - так что это, вероятно, на мне!
Мой опыт в мире Fable (до Feliz) заключался в том, что я писал все как обычные функции по большей части (например, по одному компоненту для каждого .fs). В результате я потерял множество преимуществ, которые предоставляет система React. Начиная с Feliz, мне пришлось по-настоящему погрузиться в то, как работает React (хорошая вещь, я думаю). С тех пор, как я к этому привык, я даже не задумываюсь об этом осознанно. Каждая функция, которую я пишу, которая выполняет рендеринг, является функциональным компонентом.
Если вы действительно хотите научиться идиоматически писать React, я думаю, что это действительно так же просто, как ограничить себя тем, чтобы не использовать Elmish, а использовать только функциональные компоненты / хуки в вашем демонстрационном приложении. Вы можете легко следить за всем, что написано на JS, поскольку API почти такой же.
Наличие качественного приложения с открытым исходным кодом, написанного на Feliz, определенно было бы полезно, я недавно создал для него проблему # 67. Сейчас ближе всего к нему, вероятно, само приложение docs или демо - Electron от @cmeeren .
Самый полезный комментарий
Привет @MangelMaxime!
Прежде всего, я хочу поблагодарить вас за то, что вы потратили время и силы не только на то, чтобы опробовать Feliz на проекте, но и на написание такого обширного анализа. Я уверен, что многие пользователи Fable найдут его очень полезным и информативным.
Я очень ценю такую обратную связь и открытость и считаю, что это крайне важно для того, чтобы сделать эту библиотеку наилучшей, какой она может быть вместе с ее экосистемой: молитесь:
Я расскажу о Feliz.Bulma чуть позже, потому что я считаю, что это особенное место в экосистеме. Сначала я отвечу на некоторые проблемы, которые у вас есть, которые уже можно исправить без изменений в библиотеке.
Перегрузки
onChange
На самом деле нет. Тип должен быть выведен из вашего типа сообщения следующим образом:
В зависимости от типа
ChangeGistToken
будет выведена правильная перегрузка. Когда случай DU равенChangeGistToken of string
тогда будет выбрана перегрузкаstring -> unit
. Но это также может бытьFileSelected of File
когда тип вводаfile
в этом случае будет выведена перегрузкаFile -> unit
и так далее и тому подобное. Вам не нужен синтаксический сахарev.Value
отFable.React
Обратные вызовы с несколькими аргументами
@Shmew уже затронул эту проблему, и это действительно способ решить эти типы свойств. Важно понимать, что при реализации расширений Feliz вы можете выполнять преобразования перед установкой свойства:
Следуя этой логике, вы можете внутренне преобразовать
'A -> 'B -> unit
вFunc<'A, 'B, unit>
:Это более явная версия, чем та, которая предоставляется @Shmew (как вы знаете, с привязками, вам всегда нужно немного поиграть с ними, чтобы получить их правильно). Рабочий пример этого здесь
Безопасность типов в экосистеме Feliz
Как упоминалось выше @Shmew : правильное расширение Feliz не позволяет вам писать код, который ведет себя неправильно, а ограничение типов свойств позволяет вам реализовать это. Вы можете либо создать свойства, которые возвращают
IReactProperty
например Feliz.Recharts, что обеспечивает обратную совместимость с существующими свойствами вprop
либо вы можете реализовать более специализированный типISpecialiedProperty
для поддержки только подмножество свойств при дублировании имен некоторых свойств изIReactProperty
для обеспечения обратной совместимости:Это то, что я делал с Feliz.AntDesign, например здесь, где я дублирую некоторые свойства, чтобы сделать их доступными из точки входа
button
(позже я мог бы сделать свойства более специализированными с помощью строгих типов, но сначала , обратная совместимость - это то, с чего вы впервые начинаете). Я считаю, что Feliz.MaterialUI делает аналогичные вещи для расширенияIReactProperty
а не для специализации свойств. Это подводит нас к делу Фелиз.Бульма.Дело Фелиз Бульма
До того, как был реализован Feliz.Bulma, я думал, что нет необходимости создавать расширения Feliz для фреймворков, содержащих только CSS. Feliz позволяет очень легко составлять несколько имен классов и работать с ними по условию. Теперь с неявным
yield
в F # стало еще проще. Объедините это с TypedCssClasses, и выОднако после того, как я увидел реализацию Feliz.Bulma от @Dzoukr, это
Bulma.button
,Bulma.card
и т. Д. Их действительно приятно использовать. Что касается модификаторов, я думаю, что подход Романа легко использовать, но, как вы сказали, иногда он может давать интересные результаты. Конечно, в этом отделе есть еще что улучшить, и в любом случае я думаю, что Роман проделал огромную работу, следуя видению Фелиза, создав что-то легкое для изучения и использования.Пакетное управление Feliz
Я просто хочу указать на огромную разницу в текущих
Fable.React
иFeliz
: в управлении версиями пакетов. Версии Feliz все ее экосистемы библиотек Фемто -Совместимы , которые снимают нагрузку от пользователей , чтобы вручную установить необходимые пакеты НПХ или знать , какую версию они совместимы с. Это не похоже на многие, если не на все производные библиотекиFable.React
и даже на самFable.React
, где это не так.Планы на будущее