@preact/signals-react中effect与useSignalEffect的差异探究
@preact/signals-react中effect与useSignalEffect的差异解析
核心差异
1. 生命周期绑定与自动清理
effect是全局副作用函数,不与任何React组件的生命周期绑定。组件卸载后,它的订阅不会自动终止,必须手动调用其返回的清理函数才能停止监听signal变化。useSignalEffect是React Hook,完全绑定组件的生命周期。组件挂载时启动signal订阅,卸载时会自动清理所有内部订阅,无需手动处理。
2. 依赖数组的支持
useSignalEffect不支持依赖数组参数,这是和React useEffect最关键的区别之一。它的触发逻辑完全由内部访问的signal实例决定——只要回调里访问的signal.value发生变化,就会重新执行。你尝试传入的[count]或[count.value]会被直接忽略,这就是为什么依赖数组不起作用的原因。
示例场景验证
在你的测试代码中,因为组件始终处于挂载状态,所以两者表现出一致的触发行为。但如果给组件加上条件渲染逻辑,就能看到差异:
import React, { useState } from 'react' import { effect, useSignal, useSignalEffect } from '@preact/signals-react' export default function ComputedSignalExample() { const [show, setShow] = useState(true); const count = useSignal(0); // 组件卸载后不会自动清理,需手动调用cleanup const cleanupEffect = effect(() => { console.log(`From Effect: ${count.value}`); }); // 组件卸载时自动清理订阅 useSignalEffect(() => { console.log(`From useSignalEffect: ${count.value}`); }); return ( <div> {show && ( <div> <p>The current count is: {count}</p> <button onClick={() => count.value++}>Increment</button> </div> )} <button onClick={() => { setShow(false); // 若不调用cleanupEffect,effect会继续打印count变化 // cleanupEffect(); }}>卸载组件</button> </div> ); }
当点击「卸载组件」后:
useSignalEffect会停止打印日志- 若未调用
cleanupEffect(),effect会继续监听count的变化并打印
选型建议
- 如果副作用和组件生命周期强相关(比如组件挂载时初始化、卸载时清理),优先用
useSignalEffect - 如果需要全局监听signal变化(不依赖组件存在),使用
effect并手动管理清理逻辑
内容的提问来源于stack exchange,提问作者Barnit Basnet
相关产品推荐
相关产品推荐

