How to use ref both inside and outside(parent) component?

I have parent component with this code:
return (
<div>
<div class="grid grid-cols-2 border gap-2 mx-auto min-w-[420px] max-w-[840px] px-4">
{totalPrice()}
<button onClick={() => myDialog?.showModal()}>Terms!</button>
</div>

<Dialog
text="This is terms of service text text text, do you agree? 12354123135
5645343 231E"
ref={myDialog}
/>
</div>
);
return (
<div>
<div class="grid grid-cols-2 border gap-2 mx-auto min-w-[420px] max-w-[840px] px-4">
{totalPrice()}
<button onClick={() => myDialog?.showModal()}>Terms!</button>
</div>

<Dialog
text="This is terms of service text text text, do you agree? 12354123135
5645343 231E"
ref={myDialog}
/>
</div>
);
And this is Dialog component:
function Dialog(props) {
return (
<dialog
onClick={() => {
props.ref?.close();
}}
ref={props.ref}
class="fixed inset-0 items-center justify-cente p-4"
>
<div
onClick={(e) => e.stopPropagation()}
class="border min-w-[420px] max-w-xl mx-auto bg-white p-1"
>
{props.text}
<button
onClick={() => {
props.ref?.close();
}}
>
Press me
</button>
</div>
</dialog>
);
}
export default Dialog;
function Dialog(props) {
return (
<dialog
onClick={() => {
props.ref?.close();
}}
ref={props.ref}
class="fixed inset-0 items-center justify-cente p-4"
>
<div
onClick={(e) => e.stopPropagation()}
class="border min-w-[420px] max-w-xl mx-auto bg-white p-1"
>
{props.text}
<button
onClick={() => {
props.ref?.close();
}}
>
Press me
</button>
</div>
</dialog>
);
}
export default Dialog;
So, I can open dialog from parent component because ref of dialog works as it should in the parent scope, but I can't use close() of ref of dialog element inside my Dialog component. What am I doing wrong? If I don't split this in two components then it works. But I would prefer to have this Dialog component separate and just be able to open it from a parent component.
8 Replies
TripleSmile
TripleSmileOP12mo ago
I think this tutorial is relevant maybe, but it doesn't do anything with ref inside Canvas.jsx: https://www.solidjs.com/tutorial/bindings_forward_refs?solved
bigmistqke
bigmistqke12mo ago
U can most likely solve it by making the ref a signal instead of just a let
TripleSmile
TripleSmileOP11mo ago
Interesting, thank you, I will try that It kinda works but the code looks a bit weird to me. Maybe I'm doing this wrong? 😄 I've read some information about refs but I don't understand exactly how to think about what's happening under the hood so to say. I don't fully understand what is asigned where and when...
const [myDialog, setMyDialog] = createSignal<HTMLDialogElement | undefined>();
return (
<div>
<div class="grid grid-cols-2 border gap-2 mx-auto min-w-[420px] max-w-[840px] px-4">
{totalPrice()}
<button onClick={() => myDialog()?.showModal()}>Terms!</button>
</div>

<Dialog
text="Shis is terms of service text text text, do you agree? 12354123135
5645343 231E"
ref={(el: any) => {
setMyDialog(el);
}}
myDialog={myDialog}
/>
</div>
const [myDialog, setMyDialog] = createSignal<HTMLDialogElement | undefined>();
return (
<div>
<div class="grid grid-cols-2 border gap-2 mx-auto min-w-[420px] max-w-[840px] px-4">
{totalPrice()}
<button onClick={() => myDialog()?.showModal()}>Terms!</button>
</div>

<Dialog
text="Shis is terms of service text text text, do you agree? 12354123135
5645343 231E"
ref={(el: any) => {
setMyDialog(el);
}}
myDialog={myDialog}
/>
</div>
function Dialog(props) {
return (
<dialog
onClick={() => {
props.myDialog()?.close();
}}
ref={props.ref}
class="fixed inset-0 items-center justify-cente p-4"
>
<div
onClick={(e) => e.stopPropagation()}
class="border min-w-[420px] max-w-xl mx-auto bg-white p-1"
>
{props.text}
<button
onClick={() => {
props.myDialog()?.close();
}}
>
Press me
</button>
</div>
</dialog>
);
}
export default Dialog;
function Dialog(props) {
return (
<dialog
onClick={() => {
props.myDialog()?.close();
}}
ref={props.ref}
class="fixed inset-0 items-center justify-cente p-4"
>
<div
onClick={(e) => e.stopPropagation()}
class="border min-w-[420px] max-w-xl mx-auto bg-white p-1"
>
{props.text}
<button
onClick={() => {
props.myDialog()?.close();
}}
>
Press me
</button>
</div>
</dialog>
);
}
export default Dialog;
bigmistqke
bigmistqke11mo ago
I've read some information about refs but I don't understand exactly how to think about what's happening under the hood so to say.
it can be handy to look at the compiled output in the playground. the following code:
let x = "before"

function test(props){
props.x = "after"
}
test({x})

console.log(x)
let x = "before"

function test(props){
props.x = "after"
}
test({x})

console.log(x)
would log before and not after. because refs as regular variables is a common pattern in solid, they do a custom transform for ref-props:
bigmistqke
bigmistqke11mo ago
No description
bigmistqke
bigmistqke11mo ago
but that means you can only access the ref from the parent, and not the child
No description
bigmistqke
bigmistqke11mo ago
if we would not use ref as prop, but instead use another prop-name we would get the result I shown with before/after
No description
bigmistqke
bigmistqke11mo ago
another possible solution would be to not pass a primitive, but an object
let x = {current: "before"}

function test(props){
props.x.current = "after"
}
test({x})

console.log(x.current)
let x = {current: "before"}

function test(props){
props.x.current = "after"
}
test({x})

console.log(x.current)
this would log after translated to solid's jsx:
function Child(props) {
setTimeout(() => console.log('child', props.element.current), 1000)
return (
<div ref={props.element.current}/>
);
}

function App() {
const element = {current: undefined}
setTimeout(() => console.log('parent', element.current), 1000)
return (
<Child element={element}/>
);
}
function Child(props) {
setTimeout(() => console.log('child', props.element.current), 1000)
return (
<div ref={props.element.current}/>
);
}

function App() {
const element = {current: undefined}
setTimeout(() => console.log('parent', element.current), 1000)
return (
<Child element={element}/>
);
}
would log parent HTMLDivElement and child HTMLDivElement (learned a thing or two myself while responding this question 😁 ) the props-transform is handy in 99.99% of the cases, but that 0.01 can be pretty unintuitive. if it's a good or a bad thing that solid transforms props is a topic of frequent debate in this discord. if you don't like either of those options, you can also choose to use mergeRefs from solid-primitives: https://github.com/solidjs-community/solid-primitives/tree/main/packages/refs#mergerefs probably the cleanest option

Did you find this page helpful?