Skip to content

Shmew/Feliz.UseWorker

Repository files navigation

Feliz.UseWorker Nuget

Web workers in Fable made easy, exposed as React hooks and Elmish commands all within a single project.

Includes features such as sync-fallback, message timeouts, automatic non-primitive serialization, and reactive status updates.

A worker file:

module Workers.Sort

open Feliz.UseWorker

let rng = System.Random()

let sortNumbers' () =
    Array.init 3000000 (fun _ -> rng.NextDouble() * 1000000.)
    |> Array.sort
    |> Array.sum
    |> int

let sortNumbers = WorkerFunc.Create("Sort", "sortNumbers", sortNumbers')

Elmish:

open Feliz.UseWorker

type State =
    { Count: int 
      Worker: Worker<unit,int> option
      WorkerState: WorkerStatus }

    interface System.IDisposable with
        member this.Dispose () =
            this.Worker |> Option.iter (fun w -> w.Dispose())

type Msg =
    | ChangeWorkerState of WorkerStatus
    | ExecuteWorker
    | KillWorker
    | RestartWorker
    | SetWorker of Worker<unit,int>
    | WorkerResult of int

let init = 
    { Count = 0
      Worker = None
      WorkerState = WorkerStatus.Pending }, 
    Cmd.Worker.create Workers.Sort.sortNumbers SetWorker ChangeWorkerState

let update (msg: Msg) (state: State) =
    match msg with
    | ChangeWorkerState workerState ->
        { state with WorkerState = workerState }, Cmd.none
    | ExecuteWorker ->
        state, Cmd.Worker.exec state.Worker () WorkerResult
    | KillWorker ->
        state, Cmd.Worker.kill state.Worker
    | RestartWorker ->
        state, Cmd.Worker.restart state.Worker
    | SetWorker worker ->
        { state with Worker = Some worker }, Cmd.none
    | WorkerResult i ->
        { state with Count = i }, Cmd.none

Hooks:

open Feliz.UseWorker

let render = React.functionComponent(fun () ->
    let worker,workerStatus = React.useWorker(Workers.Sort.sortNumbers)
    let count,setCount = React.useState 0

    Html.div [
        prop.children [
            ...
            Html.button [
                prop.onClick <| fun _ -> worker.invoke((), setCount) 
                prop.text "Execute"
            ]
            Html.button [
                prop.onClick <| fun _ -> worker.kill()
                prop.text "Kill"
            ]
            Html.button [
                prop.onClick <| fun _ -> worker.restart()
                prop.text "Restart"
            ]
        ]
    ])

See the full documentation with live examples here.