Extend Hooks
If you do not care about unit testing, you can extend your own functionality like this. But in this way, it is not easy to mock the extension methods.
type IComponentHook with
member hook.DataCanBeShared =
let store = hook.ServiceProvider.GetService<IShareStore>()
store.CreateCVal(nameof hook.DataCanBeShared, LoadingState<...>.NotStartYet)
member hook.LoadDataAfterRender() =
hook.AddFirstAfterRenderTask(fun () ->
task {
hook.DataCanBeShared.Publish LoadingState.start
let! result = ... call some API
hook.DataCanBeShared.Publish (LoadingState.Loaded data)
}
)
If you want to make your component unit testing friendly, you will need to do more stuff:
Define an interface.
type IMyCompHook =
abstract member DataCanBeShared: ...
abstract member LoadDataAfterRender: ...
Implement it.
type MyCompHook (hook: IComponentHook) =
interface IMyCompHook with
...
Add it to the DI container at the program start.
// Under the hood, it just registers a singleton factory function for the consumer to use.
services.AddHookService<IMyCompHook>(MyCompHook)
Use it in your component.
let myComp =
html.inject (fun (hook: IComponentHook) ->
// Every time you consume this, it will create a new instance for you.
let myCompHook = hook.GetHookService<IMyCompHook>()
...
)
Finally, when you do your testing, you can use bUnit to mock the interface as usual.