Fork me on GitHub
#re-frame
<
2018-04-09
>
Vincent Cantin02:04:40

In re-frame, what is the recommended way for a custom reagent component to receive/react to events sent from other components?

mikethompson02:04:38

@vincent.cantin your UI is a rendering of the current state in app-db. So components don't really react to events sent by other components. Instead, an event changes app-db and then that new state in app-db is rendered

Vincent Cantin03:04:04

But there are some cases where a component cannot just react to data change and need to receive events, somehow. For those special cases, is there a way for them to register an event handler just for the time where they are mounted on the dom?

Vincent Cantin03:04:54

Would it be the recommended way to do it?

mikethompson03:04:45

> where a component cannot just react to data change and need to receive events, somehow For clarity, can you give an example?

Vincent Cantin03:04:45

a leaflet map (from the js world), wrapped inside a reagent component, and which would want to receive an event like :recenter-view-on-all-marker-but-just-right-now-not-permanently

Vincent Cantin03:04:59

The event handler needs to have a reference to the right map instance which is created dynamically in the reagent component.

mikethompson03:04:09

And what does the user do to cause this?

Vincent Cantin03:04:28

the user push a button located somewhere else on the page.

mikethompson03:04:56

So that button would emit an event (a normal re-frame event)

mikethompson03:04:04

And that event would be processed by an event handler

mikethompson03:04:21

Which would update some state in app-db to indicate the users preference

mikethompson03:04:38

And there would be a subscription delivering that state to the view

mikethompson03:04:11

Then you'd use this sort of arrangement to work with a stateful js component ...

Vincent Cantin03:04:37

That's the data-driven approach, that does not fit the event's lifecycle.

Vincent Cantin03:04:14

If the user clicks on the button a second time, the map is expected to recenter again.

Vincent Cantin03:04:42

I imagine 2 ways to solve my problem, but I don't want to implement something weird, so I want to ask if the solutions are what I am supposed to do or not.

Vincent Cantin03:04:49

Solution 1: In the :component-will-mount, after the leaflet js object is created, I register an event handler which has the reference to that instance. I unregister it when the reagent component unmount.

mikethompson03:04:37

Hmm,. Its kinda like its an effecct

mikethompson03:04:09

You want to effect (mutate) the Leaflet instance

Vincent Cantin03:04:09

Solution 2: I add the leaflet js object to the app-db on mount, and I remove it when I unmount. A permanent event handler is getting the reference from the db.

mikethompson03:04:39

I see what you mean now about wanting to send an event to the Leaflet instance

mikethompson03:04:30

There's something about Solution 1 which seems more correct

mikethompson03:04:45

But I'd do it via effects

mikethompson03:04:32

So the event handler returns an effect which says that X should happen to the Leaflet instance (what you call the event to the Leaflet instance)

mikethompson03:04:05

Uggh. There's going to be a bit of plumbing.

mikethompson03:04:26

Nothing entirely natural going on here

Vincent Cantin03:04:13

Yes, so that's why I am thinking that I can not just implement a "reagent component" for leaflet, it has to be a "re-frame component".

Vincent Cantin03:04:41

Because of the plumbing involved.

mikethompson03:04:12

Not sure I understand the difference. re-frame uses reagent for components

Vincent Cantin03:04:36

reagent does *not* cover the events, the domino ...

Vincent Cantin03:04:38

Thank you for your feedback already.

mikethompson03:04:47

I'm still not following. But perhaps not important. So, thinking out aloud ... not completely convinced of this but anyway just speculating : 1. I think your button will have to emit an event [:recenter-view-on-all-marker-but-just-right-now-not-permanently 1234] where 1234 is the Leaflet instance. 2. then the event handler will have to produce the effect: {:leaflet-mutation {:id 1234 :mutation :recenter-view-on-all-marker-but-just-right-now-not-permanently} 3. Then you need the effect handler defined for :leaflet-mutation which has a way to get at the leaflet instance

mikethompson03:04:15

So now we get into the Leaflet instance getting "registered" cia component-did-mount

mikethompson03:04:25

with its id of 1234

mikethompson03:04:33

So the effect handler knows how to get at it.

mikethompson03:04:44

This is a kinda variation on your two scenarios

mikethompson03:04:54

Just a thought

mikethompson03:04:17

That's as close to idomatic re-frame as I can imagine. The mutation of the Leaflet instance is "a change to the world" so that should be modelled as an effect

mikethompson03:04:39

But ... its all pretty unusual ... I'm not sure there's really a perfect way. Easiest way might be best.

mikethompson03:04:48

Gotta go. Good luck

manuel09:04:15

hi everybody. I have a reg-sub-raw like this:

(rf/reg-sub-raw
 ::my-sub
 (fn [db _]
   (rf/dispatch [::me/event-1])
   (r/reaction (:my-result @db))))
Is there a way to trigger it on browser back button?

manuel09:04:46

basically I need to re-run the ::me/event-1 to refresh the panel

javi09:04:48

@vincent.cantin I have used the approach that @mikethompson references successfully with leaflet and other "stateful" js libs like d3, codemirror etc... ( can't share code atm, not open source yet ) 1. on component-did-mount create the lib instance and attach it to an atom 2. when props update, get the lib from the atom and use it What do you mean when you say "That's the data-driven approach, that does not fit the event's lifecycle"?

Vincent Cantin10:04:02

@fj.abanses It mean that there is a difference of life cycle between a stored data in the db and an event : The event has a meaning at the time it is fired and it theoretically dies right after being received. Data in the app-db stays until removed. The same event dispatched multiple times consecutively will mean something else than a data set at a given value multiple times.

Vincent Cantin10:04:22

In my program I am already tracking data from my custom leaflet component to add and remove markers, but events were still needed in addition.

manutter5112:04:07

@manuel I think secretary handles that sort of thing, you might want to check that out (https://github.com/gf3/secretary). Also I’d highly recommend not putting a dispatch inside a subscription — it’s too easy to get yourself into an endless-loop situation that way. If you need your app to respond to events that are not user-generated, you probably want effects (https://github.com/Day8/re-frame/blob/master/docs/Effects.md)

manuel12:04:51

@manutter51 thanks. I am using bidi at the moment, I'll see what I can do.

manutter5112:04:45

There’s also the plain old JS hook for the beforeunload event. Might be able to hook into that somehow, via an effect, though there are serious restrictions on what a beforeunload handler can do, due to past abuses.

timrichardt15:04:53

Hi all, is there a common source for this error:

e-frame: no handler registered for effect: 
Object { ns: null, name: "event", fqn: "event", _hash: 301435442,
...
I can't find the error. I never dispatch an event called "event" or something else.

timrichardt15:04:19

Happens along dispatching other events.

manutter5115:04:24

Do you have a typo somewhere in the map you return from reg-event-fx?

manutter5115:04:28

specifically a typo in a key

timrichardt15:04:49

Thanks, It was indeed in the coeffects map. If you return them as they come in the argument, they seem to contain more than the :db key. I now return {:db (:db coeffects)} and no effect is triggered.

👍 8
danielcompton22:04:32

Two small but significant fixes here ^^, 1. ClojureScript MapEntries in 1.10 aren't printed with the blue protocol browser when you're inspecting data 2. Data previews in the Event browser are now 'lazily' printed so we only pay the cost to print the size of string that is viewable, not the entire data structure. If you have a large app-db this will make a big performance difference

mikethompson23:04:09

@jeaye unfortunately we never do development using ReactNative so we're clueless about it all.

mikethompson23:04:22

Someone with direct knowledge and experience will have to step up

genRaiy23:04:40

@jeaye there is a #react-native channel

genRaiy23:04:02

but yeah, it’s a bit quiet

genRaiy23:04:00

talking of needing some help though… I need some scrolling care

genRaiy23:04:19

I’m wondering if some the CSS / flexbox stuff is preventing the scrollTop from having the desired effect so would appreciate some advice

genRaiy23:04:57

(if I remove the styles it still doesn’t work so I think it’s probably not that)

dima16:04:12
replied to a thread:

@jeaye we have good progress on making re-frame-10x work with React Native. Here are the instructions on how to set that up https://gist.github.com/dmitryn/d97f05a0ff2a653d07d696daa4880ad1