#How can I only set the ref for an element once it's been inserted into the DOM?

46 messages Β· Page 1 of 1 (latest)

leaden valve
#

I've tried a few things but it doesn't seem like the element is inserted to the DOM at the point where the ref is called, which does make a bit of sense, but I just can't find a proper escape hatch for this.

Tried:

  • Using setTimeout(..., 0) before setting
  • Checking if document.contains(...) before setting
  • Using a hacky Mutation observer, not sure if I did my best on this one but doesn't seem optimal

For background, my use case is wit using https://github.com/lxsmnsyc/solid-floating-ui/tree/main (from @regal stream). The issue seems to happen when floating-ui itself tries to resolve the parent nodes for the floating element which do not exist at the point where the element hasn't yet been inserted in the DOM.

GitHub

SolidJS bindings for Floating UI. Contribute to lxsmnsyc/solid-floating-ui development by creating an account on GitHub.

lost marten
#

How are you setting the ref?

#

I would suggest using a signal ref if you're not already

leaden valve
#

doing it pretty conventionally, so something like:

const [ref, setRef] = createSignal();

return <Show ...>
  <div ref={setRef}>...</div>
</Show>;

I do have a mergeRef from @solid-primitives/refs though

#

but I don't think it would make much of a difference

lost marten
#

Hmm, could be a bug possibly

leaden valve
#

pretty sure something could be done inside solid-floating-ui that could get around this, like making sure that the element has been inserted

#

not sure how to get to that reactively with Solid though, I can only think of having a MutationObserver

cerulean ember
#

elements are not mounted when ref is called, they are only mounted after the ref function is called, in the effect phase (unless you created the element without mounting it immediately i.e. outside the return; don't do that), which is when the floating-ui integration tries to get them

#

the problem is probably that you have it in a Show that's gone from showing to not showing, so the element isn't mounted

#

the preferred solution is to set the ref to null/undefined when the Show goes to false

#

if it isn't working on initial render then it's possible something further up is creating the element without actually mounting it other than suspense

leaden valve
#

though the ref callback does get called twice apparently

leaden valve
#

I'll try getting a reproduction out

regal stream
leaden valve
#

wasn't able to add a ErrorBoundary to this

#

so the error only appears only in the console for some reason

#

you just need to click the button

leaden valve
cerulean ember
#
-         <Popover anchor={button} visible={visible()}>
+         <Popover anchor={button()} visible={visible()}>

fixes the issue in the repro

leaden valve
leaden valve
cerulean ember
#

which would cause this if one of them was being discarded

leaden valve
cerulean ember
#

yes don't do that

leaden valve
#

What's another way to do this, like on a createMemo with an on?

cerulean ember
#

if you must, use the children helper

#
const c = children(() => props.children);
...
{typeof c() === "function" ? c()(Option) : c()}
#

though if for some reason what you're doing there somehow works the same way in dev and prod (it doesn't if hmr still adds the extra accessor), you could do

{(() => {const c = props.children; return typeof c === "function" ? c(Option) : c})()}
leaden valve
cerulean ember
#

it probably works, but i can't really say it's robust

#
const getChildren = children(() => props.children);
...
{(() => {const c = getChildren(); return typeof c === "function" ? c(Option) : c})()}

would be better

#

well that might complain about too many args

leaden valve
#

yeah, the refs being called multiple times was that, and now its gone, but the show was actually going back and forth as you mentioned LOL

cerulean ember
#

so it was both then

leaden valve
#

yeah, I was too stubborn πŸ˜†

#

thank you so much for your time man, helped me a ton

#

πŸ‘ŒπŸ»

dusky star
#

btw I did all the things that were mentioned here and it is still not working, so I had to scrap solid-floating-ui from my project 😦