How does this work?
Fun.Blazor's concept is very simple, provide a bunch of delegates to let blazor to handle.
When you write things like:
let demo =
div {
class' "cool"
}
Under the hood, it just becomes:
let demo =
NodeRenderFragment(fun comp builder index ->
builder.OpenElement(index, "div")
bulder.AddAttribute(index + 1, "class", "cool")
builer.CloseElement()
index + 2
)
type NodeRenderFragment = delegate of root: IComponent * builder: RenderTreeBuilder * sequence: int -> int
So basically, you just created a delegate and finally it will be passed to a component and let the component to manage when to render or build the dom tree. It is similar with what the razor engine will generate in csharp world.
The component can be created by adaptiview / html.comp / html.inject etc. Those components are just normal blazor components which are inherited from ComponentBase.
Before you consider to use it:
There are some pitfalls which you may keep in mind:
FSharp compiler has performance issue on intellisense for some large computation expression (CE). It is better to make single CE block smaller and single file smaller. Or use sequence like seq/list/array with childContent for better intellisense experience:
div {
attributes ...
childContent [ // ✅ it is recommended to use this when you got more than one child items
div { "hi" }
...a lot of child items
]
}
Instead of below:
div {
attributes ...
div { "hi" }
...a lot of child items ❌
}
Hot-reload
Now the default templates contain limited hot-reload support.
It is very slow to have too much file to be hot-reloaded, so you need to add // hot-reload at the top of the file you want to enable hot-reload.
For more detail you can check my blog post Hot-reload in Fun.Blazor.
Or check the document
Attribute, items position in CE
When you want to use ref attribute, you need to put it like below
div {
attributes ...
ref (fun x -> ()) // ✅
childContent [ ... ]
}
Or
div {
attributes ...
ref (fun x -> ()) // ✅
div { 1 }
div { 1 }
// ...
}