Fork me on GitHub
#reagent
<
2020-09-16
>
Chris McCormick05:09:59

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-himik07:09:10

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 McCormick07:09:06

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 McCormick07:09:22

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

Chris McCormick07:09:07

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 McCormick07:09:11

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 McCormick07:09:40

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-himik08:09:04

What class do you actually use instead of SomeClass?

Chris McCormick08:09:55

sorry it's actually not a class

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

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

p-himik08:09:47

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-himik08:09:07

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

Chris McCormick08:09:48

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

p-himik08:09:34

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 McCormick08:09:28

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 McCormick08:09:35

but yes i should check this assumption

Chris McCormick08:09:11

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-himik08:09:52

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-himik08:09:25

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 McCormick08:09:11

with-let looks perfect. thanks so much!

👍 3