You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Solid.js中Ref的正确使用方法及常见问题解决

Solid.js中正确使用Ref的方式

你遇到的问题本质是对Solid.js的Ref机制和React的useRef理解有差异,以下是错误分析和正确实现:

错误原因

  1. Ref声明在组件外:
    这种方式会让Ref变量变成全局共享的,所有MenuNavbar组件实例都会共用同一个Ref,而且Solid无法追踪这些外部变量的生命周期,因此出现computations created outside a createRoot or render will never be disposed警告——因为这些变量不会随组件卸载被销毁。

  2. 组件内直接声明未初始化的非可选变量:
    TypeScript报错Variable 'navigationOuterRef' is used before being assigned是因为TS编译时不知道Solid会在运行时自动将DOM元素赋值给这个变量,它只看到你声明了一个未赋值的变量就直接传给了ref属性。

正确实现方式

方式一:使用createRef(贴近React useRef用法)

Solid提供了createRefAPI,用法和React的useRef几乎一致,返回一个带current属性的对象,Solid会自动把DOM元素赋值给current:

import { createRef, createSignal, For } from 'solid-js';

interface LayoutNavigation {
  label: string;
}

const MenuNavbar = (props: { layoutDatas: LayoutNavigation[] }) => {
  // 创建带类型的Ref
  const navigationOuterRef = createRef<HTMLDivElement>();
  const navigationRef = createRef<HTMLUListElement>();

  const [priorityItems, setPriorityItems] = createSignal<LayoutNavigation[]>(props.layoutDatas);

  // 示例:在组件挂载后访问Ref
  // onMount(() => {
  //   console.log(navigationOuterRef.current?.offsetHeight);
  // });

  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>
    </div>
  );
};

方式二:组件内声明可选类型变量

如果不想用createRef,可以直接在组件内声明变量,给变量加上可选类型(允许undefined),这样就能通过TS检查,Solid会在运行时自动将DOM元素赋值给它:

import { createSignal, For } from 'solid-js';

interface LayoutNavigation {
  label: string;
}

const MenuNavbar = (props: { layoutDatas: LayoutNavigation[] }) => {
  // 声明为可选类型,允许初始未赋值
  let navigationOuterRef: HTMLDivElement | undefined;
  let navigationRef: HTMLUListElement | undefined;

  const [priorityItems, setPriorityItems] = createSignal<LayoutNavigation[]>(props.layoutDatas);

  // 示例:访问Ref时用可选链避免空值错误
  // onMount(() => {
  //   console.log(navigationOuterRef?.scrollWidth);
  // });

  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>
    </div>
  );
};

注意事项

  • 不管用哪种方式,都要确保在组件挂载后访问Ref(比如在onMount回调里),否则Ref的值可能是undefined或null。
  • 组件内声明的变量Ref是组件实例私有的,不会被多个实例共享,Solid会在组件卸载时自动清理相关引用,不会出现生命周期警告。

内容的提问来源于stack exchange,提问作者ShueiYang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 10:27:25