From 6c88f7c6b9d8cc6bbf615791dac973e89ae2ba9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9=20Larivi=C3=A8re?= Date: Mon, 12 Feb 2024 16:39:09 +0100 Subject: [PATCH] Improve handling of messages after Runner gets disposed --- src/Fabulous/MvuComponent.fs | 10 ++++++++-- src/Fabulous/Runner.fs | 10 +++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/Fabulous/MvuComponent.fs b/src/Fabulous/MvuComponent.fs index 379e89e5f..a93978a72 100644 --- a/src/Fabulous/MvuComponent.fs +++ b/src/Fabulous/MvuComponent.fs @@ -28,8 +28,14 @@ module MvuComponent = let ctx = new ComponentContext(1) - let runner = - new Runner((fun () -> ctx.TryGetValue(0).Value), (fun v -> ctx.SetValue(0, v)), data.Program) + let getModel () = + match ctx.TryGetValue(0) with + | ValueNone -> failwith("Model not found in ComponentContext " + ctx.Id.ToString()) + | ValueSome model -> model + + let setModel v = ctx.SetValue(0, v) + + let runner = new Runner(getModel, setModel, data.Program) ctx.LinkDisposable(runner) diff --git a/src/Fabulous/Runner.fs b/src/Fabulous/Runner.fs index 910f230a8..ba24bd339 100644 --- a/src/Fabulous/Runner.fs +++ b/src/Fabulous/Runner.fs @@ -10,6 +10,7 @@ open System.Collections.Concurrent type Runner<'arg, 'model, 'msg>(getState: unit -> 'model, setState: 'model -> unit, program: Program<'arg, 'model, 'msg>) = let mutable _activeSubs = Sub.Internal.empty let mutable _reentering = false + let mutable _stopped = false let queue = ConcurrentQueue<'msg>() let onError (message, exn) = @@ -21,7 +22,7 @@ type Runner<'arg, 'model, 'msg>(getState: unit -> 'model, setState: 'model -> un let processMsgs dispatch msg = let mutable lastMsg = ValueSome msg - while lastMsg.IsSome do + while not _stopped && lastMsg.IsSome do let model = getState() let newModel, cmd = program.Update(lastMsg.Value, model) let subs = program.Subscribe(newModel) @@ -39,7 +40,9 @@ type Runner<'arg, 'model, 'msg>(getState: unit -> 'model, setState: 'model -> un let rec dispatch msg = try - if _reentering then + if _stopped then + () // Message arrived after Runner got disposed, simply discard it + else if _reentering then queue.Enqueue(msg) else _reentering <- true @@ -74,7 +77,8 @@ type Runner<'arg, 'model, 'msg>(getState: unit -> 'model, setState: 'model -> un let stop () = try - _reentering <- true + _stopped <- true + queue.Clear() Sub.Internal.Fx.stop onError _activeSubs _activeSubs <- Sub.Internal.empty with ex ->