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?
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.
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.
in the current example I am using this library: https://wavesurfer-js.org/ but previously it has been a codemirror instance.
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
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.
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.
What class do you actually use instead of SomeClass
?
sorry it's actually not a class
(:require ["wavesurfer.js" :as wavesurfer])
... (wavesurfer/create #js {:container el})
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.
Ugh, so many typos - sorry, just woke up. :)
no problem thanks for providing some answers! i'll investigate these strategies. 🙏
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.
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
but yes i should check this assumption
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?
Oh but there is. Even duplicated, for some reason: http://reagent-project.github.io/docs/master/reagent.core.html#var-with-let
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
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
.
with-let looks perfect. thanks so much!