S
SolidJSā€¢3mo ago
gabriel

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

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 @lxsmnsyc šŸ¤–). 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
GitHub - lxsmnsyc/solid-floating-ui: SolidJS bindings for Floating UI
SolidJS bindings for Floating UI. Contribute to lxsmnsyc/solid-floating-ui development by creating an account on GitHub.
24 Replies
gabriel
gabrielā€¢3mo ago
Someone else also seems to run into this https://github.com/lxsmnsyc/solid-floating-ui/issues/6
REEEEE
REEEEEā€¢3mo ago
How are you setting the ref? I would suggest using a signal ref if you're not already
gabriel
gabrielā€¢3mo ago
yup, doing that doing it pretty conventionally, so something like:
const [ref, setRef] = createSignal();

return <Show ...>
<div ref={setRef}>...</div>
</Show>;
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
REEEEE
REEEEEā€¢3mo ago
Hmm, could be a bug possibly
gabriel
gabrielā€¢3mo ago
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
Otonashi
Otonashiā€¢3mo ago
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
gabriel
gabrielā€¢3mo ago
hmm yeah don't think that's it, logging the state that goes into the when prop on a render effect doesn't only logs once though the ref callback does get called twice apparently tried doing that but it seems like it still errors I'll try getting a reproduction out
lxsmnsyc
lxsmnsycā€¢3mo ago
there's not much to touch in solid-floating-ui though
gabriel
gabrielā€¢3mo ago
Gabriel Miranda
StackBlitz
Reproduction of issue with solid-floating-ui - StackBlitz
A Solid TypeScript project based on @floating-ui/dom, solid-floating-ui, solid-js, solid-transition-group, typescript, vite, vite-plugin-solid and csstype
gabriel
gabrielā€¢3mo ago
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 hmm, so how what do you recommend I do to avoid this kind of thing?
Otonashi
Otonashiā€¢3mo ago
- <Popover anchor={button} visible={visible()}>
+ <Popover anchor={button()} visible={visible()}>
- <Popover anchor={button} visible={visible()}>
+ <Popover anchor={button()} visible={visible()}>
fixes the issue in the repro
gabriel
gabrielā€¢3mo ago
oh missed the parenthesis šŸ˜† , then I think it might be something else than what I've thought on second thought I think this might be the issue here
Otonashi
Otonashiā€¢3mo ago
this sounds like you're calling props.children twice somewhere which would cause this if one of them was being discarded
gabriel
gabrielā€¢3mo ago
hmm yeah I actually kind of am
gabriel
gabrielā€¢3mo ago
here
No description
Otonashi
Otonashiā€¢3mo ago
yes don't do that
gabriel
gabrielā€¢3mo ago
What's another way to do this, like on a createMemo with an on?
Otonashi
Otonashiā€¢3mo ago
if you must, use the children helper
const c = children(() => props.children);
...
{typeof c() === "function" ? c()(Option) : c()}
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})()}
{(() => {const c = props.children; return typeof c === "function" ? c(Option) : c})()}
gabriel
gabrielā€¢3mo ago
yeah I'll try doing this, using children ended up needing too much type finagling
Otonashi
Otonashiā€¢3mo ago
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})()}
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
gabriel
gabrielā€¢3mo ago
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
Otonashi
Otonashiā€¢3mo ago
so it was both then
gabriel
gabrielā€¢3mo ago
yeah, I was too stubborn šŸ˜† thank you so much for your time man, helped me a ton šŸ‘ŒšŸ»
itsyoboieltr
itsyoboieltrā€¢2mo ago
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 šŸ˜¦ the only solution that worked for me is to migrate my tooltip, and popover components to corvu https://corvu.dev/docs/, which also uses floating-ui, but does not have this issue šŸ˜„
Want results from more Discord servers?
Add your server
More Posts