如何在SolidJS中传递只读Props?依赖注入场景lint问题求解
问题描述
我经常给Solid组件传递用于单例服务依赖注入的只读属性,简化示例如下,但SolidJS的lint规则抛出错误:
The reactive variable 'props.firestore' should be used within JSX, a tracked scope (like createEffect), or inside an event handler function.
这类只读Props的使用看似合理,我是否误用了SolidJS的Props?或是ESLint规则不够完善?我不想盲目禁用lint警告,希望确认正确做法。
示例代码
export const DocumentView = (props: { firestore: Firestore }) => { const query = query(collection(props.firestore), "my-collection"); const [docs, setDocs] = createSignal([]); const unsubscribeQuery = onSnapshot(query, (snapshot) => { setDocs(() => snapshot); }); onCleanup(() => unsubscribeQuery()); return ( <div> <For each={docs}>{(i) => <p>{i}</p>}</For>{" "} </div> ); };
正确做法解析
你并没有误用SolidJS的Props,这个Lint警告是因为Solid的ESLint规则对响应式变量的追踪场景做了严格校验,但你的场景属于「非响应式的单例依赖注入」,规则没识别到这种特殊情况。
解决这个问题不需要禁用警告,有两种更规范的处理方式:
1. 明确标记Props为非响应式(推荐)
因为你传递的是单例服务(比如Firestore实例),它本身不会是响应式值,你可以在解构Props时添加/* @once */注释,告诉ESLint这个Props只需要读取一次,不需要追踪:
export const DocumentView = ({ firestore /* @once */ }: { firestore: Firestore }) => { const query = query(collection(firestore), "my-collection"); const [docs, setDocs] = createSignal([]); const unsubscribeQuery = onSnapshot(query, (snapshot) => { setDocs(() => snapshot); }); onCleanup(() => unsubscribeQuery()); return ( <div> <For each={docs}>{(i) => <p>{i}</p>}</For>{" "} </div> ); };
2. 将初始化逻辑放入createEffect(适合未来可能变为响应式的场景)
如果未来这个Props有可能变成响应式(比如切换不同的Firestore实例),可以把查询初始化逻辑放到createEffect里,这样既符合Lint规则,又能自动响应Props变化并清理旧订阅:
export const DocumentView = (props: { firestore: Firestore }) => { const [docs, setDocs] = createSignal([]); createEffect(() => { const query = query(collection(props.firestore), "my-collection"); const unsubscribe = onSnapshot(query, (snapshot) => { setDocs(() => snapshot); }); // 自动清理当前订阅 return unsubscribe; }); return ( <div> <For each={docs}>{(i) => <p>{i}</p>}</For>{" "} </div> ); };
警告触发原因
Solid的Props本身是响应式的,ESLint规则会检查所有props的读取场景,如果读取不在JSX、追踪作用域(createEffect/createMemo等)或事件处理器里,就会默认认为你可能遗漏了响应式追踪。但你的场景是单例注入,不需要追踪变化,所以用/* @once */注释是最直接的适配方案。
内容的提问来源于stack exchange,提问作者JustinM

