Solid.js中Ref的正确使用方法及常见问题解决
Solid.js中正确使用Ref的方式
你遇到的问题本质是对Solid.js的Ref机制和React的useRef理解有差异,以下是错误分析和正确实现:
错误原因
Ref声明在组件外:
这种方式会让Ref变量变成全局共享的,所有MenuNavbar组件实例都会共用同一个Ref,而且Solid无法追踪这些外部变量的生命周期,因此出现computations created outside a createRoot or render will never be disposed警告——因为这些变量不会随组件卸载被销毁。组件内直接声明未初始化的非可选变量:
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
相关产品推荐
相关产品推荐

