Search code examples
solid-js

How to use Ref in Solid.js?


So i am learning and start play around with Solid.js, and I want to know how do we handle ref in solid.js like useRef in react.

I check the doc I try something like this:

      let navigationOuterRef: HTMLDivElement
      let navigationRef: HTMLUListElement
    
     const MenuNavbar = (props: {layoutDatas: LayoutNavigation[]}) => {
        
       const [priorityItems, setPriorityItems] = createSignal<LayoutNavigation[]>(props.layoutDatas);
      
      //....
    
      return (
        <div ref={navigationOuterRef} class="....">
          <ul ref={navigationRef} class="...">
            <For each={priorityItems()}>
              {(labelName) => (
                <li class="flex items-center cursor-pointer">
                  {labelName.label}
                </li>
              )}
            </For>
          </ul>
        //...

it work... but I got the warning message like

computations created outside a createRoot or render will never be disposed

So I think the issue is the fact i create the ref outside the component so without a proper context it cannot be disposed if unmounted, but if i moved the ref declaration in the component I have this error in TS

Variable 'navigationOuterRef' is used before being assigned.

so what I am doing wrong and what is the right approach ?


Solution

  • Yes, components requires you to run them under a proper owner, that is either render function, or a root created via createRoot function or another component. This is needed to build an ownership tree, a tree that show who owns whom so that when a component is disposed, its resources will be cleaned up. So, the warning message is nothing to do with refs, but about components created outside a reactive context.

    Other than that refs are handles to underlying DOM nodes. They come in two flavors: variables and functions.

    Variable forms requires you to use onMount hooks because when components are loaded, ref will be undefined, only after render phase completes they point to the actual DOM element.

    let ref;
    
    console.log(ref); // undefined
    
    onMount(() => console.log(ref)); // div
    
    <div ref={ref} />
    

    Why they are not available immediately is because Solid runs the assignment operation while building the DOM tree.

    <div ref={el => ref=el} /> 
    

    Variable form is basically a syntax sugar for the function form.

    Since ref is not available initially, the correct type of the ref element is:

    let navigationOuterRef: HTMLDivElement | undefined;
    

    If you do not put undefined, you will have the type error:

    Variable 'X' is used before being assigned
    

    Function form receives the DOM element as soon as the DOM node becomes available:

    function handleRef(ref: HTMLDivElement) {
      console.log(ref); // div
    }
    
    <div ref={handleRef} />
    

    Compiled code invokes the ref function while creating the DOM tree.

    https://www.solidjs.com/docs/latest#ref