reagent

A minimalistic ClojureScript interface to React.js http://reagent-project.github.io/
Chris McCormick 2020-09-16T05:41:59.020600Z

Hello! I'm using :ref and calling a library that wants to bind itself to the dom. What's the best way to store the instance the library creates so I can tear it down again when :ref is null upon the next re-render?

p-himik 2020-09-16T07:36:10.020700Z

I'm not sure I fully understand the picture, especially the "tearing down" part, but whatever value you have, I'd store it the same way the :ref is stored.

Chris McCormick 2020-09-16T07:51:06.020900Z

sorry for being unclear. [:div {:ref (fn [el] (SomeClass. el))} "hello"] so the Javascript class takes el and manipulates the dom under it. it has a bunch of internal state and a .destroy method. what i want is when this :div is destroyed because of a repaint taht i can also destroy the javascript class.

Chris McCormick 2020-09-16T07:51:22.021100Z

in the current example I am using this library: https://wavesurfer-js.org/ but previously it has been a codemirror instance.

Chris McCormick 2020-09-16T07:52:07.021400Z

the wavesurfer instance has a bunch of functionality including maintaining some webaudio objects etc. so i need to .destroy it when the div element is re-painted

Chris McCormick 2020-09-16T07:53:11.021600Z

at the moment i have a global non-reagent atom which i store the wavesurfer instance in, but i am wondering if there is a cleaner way to do this. ideally when :ref is called i could get access to the previous dom element and store the instance on that.

Chris McCormick 2020-09-16T07:53:40.021800Z

not a big deal to do it this way but since i find myself quite often doing this i wondered if there is a cleaner way.

p-himik 2020-09-16T08:04:04.022Z

What class do you actually use instead of SomeClass?

Chris McCormick 2020-09-16T08:07:55.022200Z

sorry it's actually not a class

(:require ["wavesurfer.js" :as wavesurfer])

... (wavesurfer/create #js {:container el})

p-himik 2020-09-16T08:11:47.022500Z

I can't find anywhere in the documentation that you must or even should call destroy when the corresponding DOM element is removed from the DOM. I think the only reason to call destroy is when you want to detach WaveSurfer from some element without removing the element itself. Otherwise, when the corresponding DOM node is destroyed, WaveSurfer and everything that it holds should end up garbage collected. Unless the web audio API explicitly prevents some things from being GCed... I have no idea if that's the case, but I wouldn't be surprised. In any case, just use a form-3 component or reagent.core/with-let and save the result of wavesurfer/create in an atom within the outer let of the form-3 component or within with-let. In the ref function, you have to check if the ref value is nil or not. If it is, destroy the old wavesurfer instance (if there's one). If it is not, still destroy the old instance but also create a new one.

p-himik 2020-09-16T08:13:07.023100Z

Ugh, so many typos - sorry, just woke up. :)

Chris McCormick 2020-09-16T08:14:48.023300Z

no problem thanks for providing some answers! i'll investigate these strategies. 🙏

p-himik 2020-09-16T08:16:34.023500Z

Since it's not clear whether you should call destroy at all (unless I just missed something in the documentation), it also makes sense to ask on some WaveSurfer support outlet about it.

Chris McCormick 2020-09-16T08:17:28.023700Z

i am pretty sure the webaudio elements it creates will not be garbage collected if the dom element the UI is attached to is removed from the document

Chris McCormick 2020-09-16T08:17:35.023900Z

but yes i should check this assumption

Chris McCormick 2020-09-16T08:19:11.024100Z

there doesn't appear to be any documentation for reagent.core/with-let do you know where i can find out more about what this does?

p-himik 2020-09-16T08:21:17.024300Z

Oh but there is. Even duplicated, for some reason: http://reagent-project.github.io/docs/master/reagent.core.html#var-with-let

p-himik 2020-09-16T08:21:52.024500Z

It was first introduced in this post, there's also an example of how to use it: https://reagent-project.github.io/news/news060-alpha.html

p-himik 2020-09-16T08:23:25.024700Z

BTW above I mentioned a form-3 component. I just realized that I wanted to say form-2. And with-let basically replaced form-2, and even form-3 in the simplest case where you just need :component-did-mount and :component-will-unmount.

Chris McCormick 2020-09-16T08:24:11.024900Z

with-let looks perfect. thanks so much!

1👍
p-himik 2020-09-16T07:36:10.020700Z

I'm not sure I fully understand the picture, especially the "tearing down" part, but whatever value you have, I'd store it the same way the :ref is stored.

Chris McCormick 2020-09-16T07:51:06.020900Z

sorry for being unclear. [:div {:ref (fn [el] (SomeClass. el))} "hello"] so the Javascript class takes el and manipulates the dom under it. it has a bunch of internal state and a .destroy method. what i want is when this :div is destroyed because of a repaint taht i can also destroy the javascript class.

Chris McCormick 2020-09-16T07:51:22.021100Z

in the current example I am using this library: https://wavesurfer-js.org/ but previously it has been a codemirror instance.

Chris McCormick 2020-09-16T07:52:07.021400Z

the wavesurfer instance has a bunch of functionality including maintaining some webaudio objects etc. so i need to .destroy it when the div element is re-painted

Chris McCormick 2020-09-16T07:53:11.021600Z

at the moment i have a global non-reagent atom which i store the wavesurfer instance in, but i am wondering if there is a cleaner way to do this. ideally when :ref is called i could get access to the previous dom element and store the instance on that.

Chris McCormick 2020-09-16T07:53:40.021800Z

not a big deal to do it this way but since i find myself quite often doing this i wondered if there is a cleaner way.

p-himik 2020-09-16T08:04:04.022Z

What class do you actually use instead of SomeClass?

Chris McCormick 2020-09-16T08:07:55.022200Z

sorry it's actually not a class

(:require ["wavesurfer.js" :as wavesurfer])

... (wavesurfer/create #js {:container el})

p-himik 2020-09-16T08:11:47.022500Z

I can't find anywhere in the documentation that you must or even should call destroy when the corresponding DOM element is removed from the DOM. I think the only reason to call destroy is when you want to detach WaveSurfer from some element without removing the element itself. Otherwise, when the corresponding DOM node is destroyed, WaveSurfer and everything that it holds should end up garbage collected. Unless the web audio API explicitly prevents some things from being GCed... I have no idea if that's the case, but I wouldn't be surprised. In any case, just use a form-3 component or reagent.core/with-let and save the result of wavesurfer/create in an atom within the outer let of the form-3 component or within with-let. In the ref function, you have to check if the ref value is nil or not. If it is, destroy the old wavesurfer instance (if there's one). If it is not, still destroy the old instance but also create a new one.

p-himik 2020-09-16T08:13:07.023100Z

Ugh, so many typos - sorry, just woke up. :)

Chris McCormick 2020-09-16T08:14:48.023300Z

no problem thanks for providing some answers! i'll investigate these strategies. 🙏

p-himik 2020-09-16T08:16:34.023500Z

Since it's not clear whether you should call destroy at all (unless I just missed something in the documentation), it also makes sense to ask on some WaveSurfer support outlet about it.

Chris McCormick 2020-09-16T08:17:28.023700Z

i am pretty sure the webaudio elements it creates will not be garbage collected if the dom element the UI is attached to is removed from the document

Chris McCormick 2020-09-16T08:17:35.023900Z

but yes i should check this assumption

Chris McCormick 2020-09-16T08:19:11.024100Z

there doesn't appear to be any documentation for reagent.core/with-let do you know where i can find out more about what this does?

p-himik 2020-09-16T08:21:17.024300Z

Oh but there is. Even duplicated, for some reason: http://reagent-project.github.io/docs/master/reagent.core.html#var-with-let

p-himik 2020-09-16T08:21:52.024500Z

It was first introduced in this post, there's also an example of how to use it: https://reagent-project.github.io/news/news060-alpha.html

p-himik 2020-09-16T08:23:25.024700Z

BTW above I mentioned a form-3 component. I just realized that I wanted to say form-2. And with-let basically replaced form-2, and even form-3 in the simplest case where you just need :component-did-mount and :component-will-unmount.

Chris McCormick 2020-09-16T08:24:11.024900Z

with-let looks perfect. thanks so much!

1👍