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

@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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 18:52:45