Fork me on GitHub
#reagent
<
2015-11-19
>
ulsa11:11:56

I have a div that's only rendered on a certain page. How and where do I initialize a JS library that wants that div?

ulsa11:11:54

If I do it on document.ready, that div might not be in the DOM.

mccraigmccraig11:11:18

@ulsa: here's a component which shows how to get the dom-node ... you can init a lib in :component-did-mount - https://www.refheap.com/46cade5b0ac1fe8774c21986a

ulsa11:11:45

yes, of course!

mccraigmccraig11:11:52

in case you haven't already seent it, https://github.com/Day8/re-frame/wiki/Creating-Reagent-Components is very helpful on the different ways to create components

ulsa11:11:04

I'm in re-frame actually, so I should have remembered that. Thanks again. Need more coffee.

ulsa11:11:02

worked like a charm, life is so good now

ulsa14:11:05

when I switch language, I need to run destroy on a third-party component, and then run the code in :component-did-mount; what's a good way of achieving this?

jstew15:11:03

ulsa: Have you tried extracting the code into a function and calling it on both :component-did-mount and :component-will-unmount?

jstew15:11:06

nm, misread that, you don't need the code in comonent-will-unmount, it appears.

jstew15:11:21

The 3rd party component probably has it's own lifecycle functions, too?

ulsa15:11:26

I would like to trigger an unmount and then a mount, basically, from outside (eg a re-frame handler)

ulsa15:11:25

yeah, I haven't even looked at its lifecycle stuff, figured all I needed was to call destroy on unmount and then create it again

jstew15:11:58

@ulsa: https://github.com/Day8/re-frame/wiki/Creating-Reagent-Components (Check out the section on Form-3 components). You could probably put the code in :component-did-mount and :component-will-unmount, and possibly call render-component again somewhere. In re-frame, you can'd do that in a handler so you would have to figure out a hacky way to re-render that component.

jstew15:11:26

I love and hate reframe simple_smile

mccraigmccraig15:11:58

@ulsa: dyu not just want to set something in your state which causes the enclosing component to re-render without the component you want to unmount ?

ulsa15:11:47

To be concrete, I want to switch language in a calendar. The language is given in the constructor, so I need to destroy it and re-create it.

ulsa15:11:39

I've tried a metadata key with @lang in render, but it doesn't work

ulsa15:11:53

so I should call destroy in will-unmount, and initialize in did-mount, right?

ulsa15:11:04

but how do I trigger the actual unmount and mount?

ulsa15:11:47

btw, the metadata thing is a tip from React community, put a key on the root element of the component and it will re-render (re-mount?) on change; didn't work for me

ulsa15:11:32

the calendar goes away, but doesn't come back

jstew15:11:59

I have to figure out how to stop slack from doing that simple_smile

ulsa15:11:25

I call unmount and then render on the whole app in the switch language handler, and that seems to work

ulsa15:11:29

I would like to do it on just the calendar, but I can experiment with that now that it works on some level

jstew15:11:27

I bet you could add something to your state, like some hidden content, even and hook into :component-will-update instead of mounting and unmounting. That seems like it should work. Seems like it could be less hacky as well.

jstew16:11:02

using that you would subscribe to something like language in the app-db, put the language right in your component (but hidden somewhere), do initialization in component-did-mount and refresh in component-did-update.

ulsa16:11:55

hmm, re-frame docs say ratom change doesn't trigger component update lifecycle methods, that's what led me to the unmount/mount path

ulsa16:11:56

"But ... when the rerender is re-run because an input ratom changed, Lifecycle functions are not run. So, for example, component-did-update will not be called on the Component. Careful of this one. It trips people up."

jstew16:11:43

Ah. Well there goes THAT idea simple_smile

ulsa16:11:24

The thing is, the calendar has to be called with "destroy" and then created again with the new language, and the DOM node has to exist before create is called. As far as I can tell, unmount/mount is the only way to achieve this.

ulsa16:11:08

Maybe some other ways can be discovered by looking at a plain JS example, as can be seen in the source for this page http://fullcalendar.io/js/fullcalendar-2.4.0/demos/languages.html

mccraigmccraig16:11:40

ulsa: how about hiding the old calendar, creating a second, new, calendar component, then removing the old-calendar component

mccraigmccraig16:11:03

pretty fugly though

ulsa16:11:21

how would that look like in pseudo?

mccraigmccraig16:11:45

ulsa: hold on though - i have at least one component where :component-did-update is called after re-render and an ratom changes

jstew16:11:06

If he wants to use did-update he can use props for the component instead of an ratom. I think he wants to completely destroy it and create a new one because his 3rd party javascript calendar won't work with old HTML content, if I understand correctly.

ulsa16:11:16

yes, I think that's how it is

ulsa16:11:59

anyway, I'll look into did-update and see what I can do

jstew16:11:45

I feel your pain though, I wish it was easier to use 3rd party javascript widgets with react.

ulsa16:11:21

cool, I put (destroy) (create) in did-update, removed my unmount/mount calls from handler, added @lang before element in render, and it seems to work nicely

ulsa16:11:24

so that doc thing was a red herring?

mccraigmccraig16:11:08

where is the doc thing from @ulsa ?

jstew16:11:52

I think the doc was referring to passing a ratom to a component without dereferencing it first? The ratom is still the same ratom so nothing actually changes.

ulsa16:11:35

so an "input ratom" is what?

jstew16:11:25

(defn my-component [input-ratom] (fn [] [:div @input-ratom])) vs (defn my-component [input-prop] (fn [input-prop] [:div input-prop])) I think.

jstew16:11:15

IOW: don't pass ratoms into components because your components won't see the change (the ratom istelf doesn't change, only the value).

ulsa16:11:47

yes, but the component won't even re-render if an input ratom's value has changed, but in that doc it says even if the component re-renders, lifecycle methods won't be called; I'm confused

jstew16:11:08

That's confusing to me as well, since according to react docs when the state changes or the props change, those lifecycle methods are called.

ulsa16:11:30

how best to post code snippets?

ulsa16:11:48

50 lines

mccraigmccraig16:11:10

refheap has nice emacs integration if you are an emacs user

ulsa16:11:29

I mean here

mccraigmccraig16:11:01

right, you post from emacs to refheap, which copies a link the the clipboard, and then paste the link in here

mccraigmccraig16:11:39

but there are probably some funky slack integrations to help too

ulsa17:11:37

ok, so here is what I think is all the code I needed, enjoy: https://www.refheap.com/111872

ulsa17:11:16

I identified three cases: page reload (render + did-mount), figwheel reload (will-unmount + render + did-mount), and manual lang switch (render + did-update)

grav21:11:09

@ulsa: as I see it, these three cases in Reagent do not differ from how React works?

grav21:11:25

Ie, Reagent follows React consistently.