-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
subscribing to external events and cleaning them when component is removed #59
Comments
I started by creating a helper for generating a bus: -- | Create an async bus for dom events
eventBus :: EventType -> Boolean -> EventTarget -> Effect (Bus.BusR Event)
eventBus eventType capture target = do
Tuple readBus writeBus <- Bus.make <#> Bus.split
listener <- eventListener \event -> launchAff_ $ Bus.write event writeBus
addEventListener eventType listener capture target
pure readBus then my I used a wrapper component which looks like this: editor :: forall a. Widget HTML a
editor = do
window <- liftEffect HTML.window
-- create the event bus here
resizeBus <- liftEffect $ eventBus (EventType "resize") true (Window.toEventTarget window)
-- put the bus into the state, so the inner component can listen to events
tea (defaultState resizeBus) editor' $ handleAction >>> runEditorM -- This uses a custom version of `tea` I made
-- unsubscribing logic would probably have to sit here, haven't implemented that yet.
where
defaultState :: Bus.BusR Event -> EditorState
defaultState =
{ ... -- more state here
, resizeBus: _
} Then the inner component is trivial: editor' :: EditorState -> Widget HTML EditorAction
editor' state = do
-- This will either return a dom event from within htmlSutff, or a resize event, whichever finishes first.
htmlStuff -- The rendering stuff is put here
<|> resizeEvent
where
resizeEvent = liftAff $ Bus.read state.resizeBus $> Resize This feels like a hack, and wouldn't handle unsubscribing too well (eg: a change of route won't trigger it), but it's the first thing I could come up with and works fine for now |
doesnt
yes |
yep, I think that's the biggest problem rn |
I am using routing to drive this sort of set up/tear down logic when I need it in my Concur app. So listen to routes using |
Here is some more info on my approach. I have quite a simple API, not unlike It looks like this: myWidget :: forall a b. StateT (MyState b) (Widget HTML) a
myWidget = do
void $ runOnce (log "subscribe home") (log "cancel home")
D.div' [ D.h1' [D.text " You are on the Homepage"]]
...
runOnce ::
forall a b.
Effect a ->
Effect Unit ->
StateT (MyState b) (Widget HTML) (Maybe a) And I haven't forgotten about cleaning events up. When you are done with It's a nice API, which has sufficed for my rather large commercial web app. I think it could be expanded on quite a bit. To see it in action I have put together an example. You can just drop this into the examples folder of https://gist.github.com/ajbarber/2fd3bc86be0e8cd1acc9e3602bf5be82 |
I looked into this a little further. So the above works okay, I suppose, if you have routing set up for your application. But perhaps you are integrating concur into an existing React JS application where you don't have control of routing, or perhaps you simply would prefer to leverage the React lifecycle events. In this vein I had a little look at it and providing an API, something very basic like -- Widget v a is a never ending widget, as there is no concept of a
-- component which returns something in React!
runAsComponent :: forall v a. Effect Unit -> Effect Unit -> Widget v a -> Widget v a should be really quite simple. As a first draft API, really the first thing that came into my head, you would provide The important thing is such an API would only make sense to be used on never ending widgets. Which I believe is what I believe the OP was trying to achieve. I haven't looked at the OP's provided code or links, but as a simple example, I just scratched around with hooking an unMount effect to the greeting widget which prints "HELLO!", in the loginWidget :: forall a. Widget HTML a
loginWidget = runTask do
u <- currentUser
runAsComponent (log "hello") (log "goodbye") (D.div'[ D.text "HELLO!" ])
|
Pushed something to react-component-lifecycle-api-idea . To see a minimal example: Make the below change to - D.div'
- [ D.text "HELLO!"
- ]
+ runAsComponent (log "hello") (log "goodbye") (D.div'[ D.text "HELLO!" ]) This hooks you'll need this import too +import Concur.React (runAsComponent) then watch the console as you log out, as described above. Ps: to incorporate this branch in your project you would need something like
in your packages.dhall |
I am rewriting keyboard example with
FRP.Event
srghma@1204045
and don't know how to
bracket
the widget to cleanup withstopListeningKeydownEvent
could someone help me
P.S.
in future I'll have to also uncomment the
toggleEvents
button and NOT ONLY subscribe onInitialize
event, but also being able to unsubscribe/resubscribe with this toggle buttonin halogen this is similar to this example https://github.com/purescript-halogen/purescript-halogen/blob/master/examples/keyboard-input/src/Main.purs AND would be implemented with
H.subscribe
https://github.com/purescript-halogen/purescript-halogen/blob/c4e3107f55485e2ca7503aec624be43a8e3f78b3/src/Halogen/Query/HalogenM.purs#L172which allows user to finalize manually, BUT also finalizes when component is destroyed
Maybe H.SubscriptionId
inState
@mateiadrielrafael, you are writing
Halogen makes subscribing to external events (eg: window resizing) a lot easier
do You know how to accomplish this? could you help, please
The text was updated successfully, but these errors were encountered: