Comments (9)
@MangelMaxime My response was a bit robotic. Thank you for providing a stop gap solution. Saw you on some commits when I dug into Elmish.HMR this weekend. Y'all are awesome. And I'd like to contribute something too.
from elmish.
@et1975 I have some ideas now and I would be glad to help with this.
from elmish.
One way, to workaround the problem is to setup your event listener inside of a React hooks.
This way you can create the listener and have it disposed when the component is not loaded anymore.
There is an example using Fable.React syntax in this blog post. If you are using Feliz, the principle is the same.
from elmish.
I don't like this approach. It leaks react OO / framework stuff into user code. I'd rather add to Elmish's capabilities if we can find the right abstraction.
from elmish.
Current beta lets you do something like that albeit not at subscription, but at the program level - via termination handler.
You could craft a sub-program for a page if you want to go that route.
Doing it via subscriptions though is a bit trickier - the problem with letting elmish itself decide when to call unsubscribe
cannot be glassed over, since elmish is platform-agnostic we need to let the subscription itself decide when to to that.
This is one of the aspects that came out of #183, the plan is to reimplement subscriptions and make them more Elm-like in a way that would let a subscription body decide, based on the current state, if it wants to suspend handling the external events. And the next model change should be able to resume to keep subscriptions management as simple as it is in Elm.
I took a stab at it but it needs more time than I'm currently able to spend on it. There are several challenges:
- it requires "upsert" semantics and either the complexity is offloaded into the subscription or each sub would need an "identity" - getting every state change as input into the sub we need to avoid creating multiple handlers on underlying emitters, so in you example elmish would need to execute
listener
a) idempotently and b) be able to enact changes over time. - the subs need to remain composable - like views, there's parent-child composition we need to be able to express
from elmish.
Doing it via subscriptions though is a bit trickier - the problem with letting elmish itself decide when to call unsubscribe cannot be glassed over, since elmish is platform-agnostic we need to let the subscription itself decide when to to that.
I agree. I was initially thinking of HMR, and that Elmish needs to be aware of running subs for transparent cleanup. But the user should have agency to stop them as well as start them. Other platforms have hot reload now, right? (Been a long time since I did other than web and apis.) Usable for them as well.
Just running the subscription fn with current model is easily possible now.
module App =
let subscriptions currentModel : Cmd<Msg> =
...
let liveSub (model, cmd) =
model, Cmd.batch [ App.subscriptions model; cmd ]
Program.mkProgram (App.init >> liveSub) (App.update >> liveSub) App.view
...
But this does not handle unsubscribes. That's why I open the issue.
from elmish.
I dug into Elm's source. Subs essentially run Tasks. Long-running tasks return their own stop fn like in my OP, so they can be stopped with Process.kill. Tasks can also stop themselves by running the provided callback fn, which is otherwise analogous to dispatch. The Elm HMR module I found monkey-patches Elm's task/scheduling fns to capture the Task stop fns and call them on hot reload.
Subs are data (kinda -- plus msg tag fn). Subs are centrally tracked *. Which is why they can be canceled by just not returning one next time subscribe is called. Subs eventually create Tasks. Bear in mind that Task return values are constrained to be Result-like. AFAICT a task emits exactly 1 msg and only on its exit. To send multiple msgs, the task has to spawn additional tasks. To send zero msgs, the task has to run indefinitely until killed.
* Tracking. The compiler/platform tracks subs by the module which created it. E.g. Time.every belongs to Time module. These are called effect modules, use the keyword effect
and provide fns like onEffect to handle sub changes. Whenever a call to subscribe returns different (I assume) subs than last time, the platform calls each affected (I assume) module's onEffect with all its current subs and its state (similar purpose to model). The module then compares the updated subs with its previous state and then starts or stops tasks as needed and updates state. Time, for example, uses 1 task per interval, then each interval has a list of "taggers" that will receive msgs when the interval fires. Of course, effect modules can only be created by the Elm inner circle.
from elmish.
Do you want me to close this and work under other issue? Or work under this one?
from elmish.
Closing as duplicate of #183
from elmish.
Related Issues (20)
- Subscribe to DOM events via `Program.withSubscription` HOT 2
- How to pass an external event into a program? HOT 30
- Zaid's fromAsync Cmd HOT 3
- Cmd helpers for checking success by option HOT 4
- Double subscribe when dispatching during sub startup
- None of the duplicate subscriptions should be started HOT 12
- Subscription doc updates for v4
- Is there an expected time to get to a stable version of v4 HOT 2
- Elmish for WebSharper apps HOT 4
- Question about FSharp.Core version HOT 4
- Cmd.OfFunc.whatever HOT 9
- Docs: String.replicate piece raises an exception HOT 1
- Remove redundant Subscription trace logs HOT 7
- Replacement with ofEffect for ofSub not working as in v3? HOT 3
- Proposal: port Elm's virtual dom to work with Feliz HOT 4
- [Question] Elmish way of disposing component dependencies HOT 1
- Suggestion: Cmd.OfTask.attempt with untyped Task HOT 1
- How to dispose of `Cmd.ofEffect` events handler? HOT 2
- FuncUI TextBox.onTextChange issues HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from elmish.