Closed sWW26 closed 2 years ago
Hello @sWW26, in theory, if your component is not loaded anymore in the DOM the Elmish application is destroyed and so will not continue generating messages.
When you say "leave the page" is the Elmish component removed from the DOM or just hidden by something else?
That's correct the component is removed, however the update function is still processing messages then raising new commands through Cmd.ofAsync. I'll try and put together a simple example.
I've made the smallest example I could think of to show my issue, click the "Start polling API" button once and it'll start printing to the console once per second. If you then click the "Navigate" button FirstComponent
is removed but you'll see the console messages continue.
open System
open Feliz
open Feliz.UseElmish
open Elmish
open Browser.Dom
type Msg =
| PollApi
let init () =
(), Cmd.none
let update msg () =
match msg with
| PollApi ->
let pollApi () =
printfn $"Making API call at {DateTime.Now}"
Async.Sleep 1000
() , Cmd.OfAsync.perform pollApi () (fun () -> PollApi)
[<ReactComponent>]
let FirstComponent navigateAway =
let state, dispatch = React.useElmish(init, update, [||])
Html.div [
Html.div "FirstComponent"
Html.button [
prop.text "Start polling API"
prop.onClick (fun _ -> dispatch PollApi)
]
Html.button [
prop.text "Navigate"
prop.onClick (fun _ -> navigateAway())
]
]
[<ReactComponent>]
let SecondComponent() =
Html.div "SecondComponent"
[<ReactComponent>]
let App() =
let hasNavigatedAway, updateHasNavigatedAway = React.useState(false)
if hasNavigatedAway then SecondComponent() else FirstComponent (fun () -> updateHasNavigatedAway true)
ReactDOM.render(App(), document.getElementById "app")
Achieved what I needed by:
CancellationTokenSource
on the model.CancellationToken
to the async call using the Cmd.ofAsyncWith
helperIDisposable
on the model so I can call Cancel()
on the CancellationTokenSource
I have an application where a component using
useElmish
is polling the server while a condition is true, in a similar fashion to the Tick example in https://zaid-ajaj.github.io/the-elmish-book/#/chapters/commands/async-recursive-updates. The problem I'm having is that when I leave the page contianing said component the dispatch loop continues to run causing unneccessary API calls.What's the best approach to stop messages from being processed inside the
useElmish
dispatch loop once the component is destroyed? I see if state implementsIDisposable
it will be called but I'm not sure how this could be used to clean up outstanding recursive messages.