Created
July 19, 2023 16:51
-
-
Save OnurGumus/c7c398cbba75955aa6ad45f08ccc4f28 to your computer and use it in GitHub Desktop.
nile
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Fable.Elmish.Nile | |
open Elmish | |
open FSharp.Control | |
open FSharp.Control.Core | |
[<RequireQualifiedAccess>] | |
module Program = | |
/// Uses `stream` to transform a stream of messages dispatched from the view | |
/// and a stream of updates to a stream of messages dispatched to `update`. | |
/// `stream` is only called once. | |
let withStream (stream: IAsyncObservable<_> -> IAsyncObservable<_> -> IAsyncObservable<_>) (program: Program<_, _, _, _>) = | |
let (modelObserver, modelObservable) = AsyncRx.subject () | |
let (messageObserver, messageObservable) = AsyncRx.subject () | |
let messages = stream modelObservable messageObservable | |
let mutable dispatch = ignore | |
let msgObserver = | |
{ new IAsyncObserver<'msg> with | |
member __.OnNextAsync x = async { | |
dispatch x | |
} | |
member __.OnErrorAsync err = async { | |
() | |
} | |
member __.OnCompletedAsync () = async { | |
() | |
} | |
} | |
let mutable initState = None | |
let init' fn arg = | |
let (model, cmd) = fn arg | |
initState <- Some (None, model) | |
(model, cmd) | |
let update' fn msg model = | |
let (model, cmd) = fn msg model | |
modelObserver.OnNextAsync (Some msg, model) |> Async.StartImmediate | |
(model, cmd) | |
let mutable hasSubscription = 0 | |
let mutable subscription = AsyncDisposable.Empty | |
let view' fn model dispatch' = | |
dispatch <- dispatch' | |
// Wait with subscribing until we have a `dispatch`, otherwise `startWith` messages would get lost | |
#if FABLE_COMPILER | |
if hasSubscription = 0 then | |
hasSubscription <- 1 | |
#else | |
if System.Threading.Interlocked.Exchange(&hasSubscription, 1) = 0 then | |
#endif | |
async { | |
let! sub = messages.SubscribeAsync msgObserver | |
subscription <- sub | |
} | |
|> Async.Start' | |
initState |> Option.iter (modelObserver.OnNextAsync >> Async.StartImmediate) | |
initState <- None | |
fn model (messageObserver.OnNextAsync >> Async.StartImmediate) | |
program |> Program.map init' update' view' id id id |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment