Skip to content

Commit

Permalink
feat: Program functions for StreamRendering
Browse files Browse the repository at this point in the history
  • Loading branch information
Tarmil committed May 23, 2024
1 parent 14dec57 commit a2e27b4
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 4 deletions.
18 changes: 15 additions & 3 deletions src/Bolero/Components.fs
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,7 @@ and [<AbstractClass>]
with _ -> () // fails if run in prerender
)

override this.OnInitialized() =
base.OnInitialized()
override this.OnInitializedAsync() =
let setDispatch d =
dispatch <- d
program <-
Expand All @@ -207,12 +206,25 @@ and [<AbstractClass>]
id id
(fun _ model dispatch -> setState model dispatch)
id id
runProgramLoop <- Program'.runFirstRender this program

let updateInitState, initModel, loop = Program'.runFirstRender this program
runProgramLoop <- loop
setState <- fun model dispatch ->
match oldModel with
| Some oldModel when this.ShouldRender(oldModel, model) -> this.ForceSetState(model, dispatch)
| _ -> ()

match this.StreamingInit with
| None ->
Task.CompletedTask
| Some init ->
task {
let! model, cmd = init initModel
updateInitState model cmd
}

member val internal StreamingInit : ('model -> Task<'model * Cmd<'msg>>) option = None with get, set

member internal this.InitRouter
(
r: IRouter<'model, 'msg>,
Expand Down
40 changes: 40 additions & 0 deletions src/Bolero/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,48 @@
module Bolero.Program

open System.Reflection
open System.Threading.Tasks
open Elmish

/// <summary>
/// Create a simple program for a component that uses StreamRendering.
/// </summary>
/// <param name="initialModel">The model that is shown initially.</param>
/// <param name="load">Load the model to be stream-rendered.</param>
/// <param name="update">The Elmish update function.</param>
/// <param name="view">The Elmish view function.</param>
let mkSimpleStreamRendering
(initialModel: 'model)
(load: 'model -> Task<'model>)
(update: 'msg -> 'model -> 'model)
(view: 'model -> Dispatch<'msg> -> Node)
: Program<'model, 'msg> =
Program.mkSimple (fun (comp: ProgramComponent<'model, 'msg>) ->
comp.StreamingInit <- Some (fun x -> task {
let! model = load x
return model, Cmd.none
})
initialModel)
update view

/// <summary>
/// Create a program for a component that uses StreamRendering.
/// </summary>
/// <param name="initialModel">The model that is shown initially.</param>
/// <param name="load">Load the model to be stream-rendered.</param>
/// <param name="update">The Elmish update function.</param>
/// <param name="view">The Elmish view function.</param>
let mkStreamRendering
(initialModel: 'model)
(load: 'model -> Task<'model * Cmd<'msg>>)
(update: 'msg -> 'model -> 'model * Cmd<'msg>)
(view: 'model -> Dispatch<'msg> -> Node)
: Program<'model, 'msg> =
Program.mkProgram (fun (comp: ProgramComponent<'model, 'msg>) ->
comp.StreamingInit <- Some load
initialModel, [])
update view

/// <summary>
/// Attach `router` to `program` when it is run as the `Program` of a `ProgramComponent`.
/// </summary>
Expand Down
11 changes: 10 additions & 1 deletion src/Bolero/ProgramRun.fs
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,17 @@ module internal Program' =

reentered <- true
setState model dispatch
fun () ->
let mutable cmd = cmd

let updateInitState m cmd' =
setState m dispatch
state <- m
cmd <- cmd @ cmd'

let run () =
cmd |> Cmd.exec (fun ex -> onError ("Error intitializing:", ex)) dispatch
activeSubs <- Subs.diff activeSubs sub |> Subs.Fx.change onError dispatch
processMsgs ()
reentered <- false

updateInitState, model, run

0 comments on commit a2e27b4

Please sign in to comment.