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

如何在React框架中实现createSignal方法?

在React中实现createSignal

你给出的AutoCounter组件存在典型的useState闭包陷阱:因为useEffect依赖为空数组,回调里的c捕获的是初始渲染时的状态值(0),导致每次调用set(c + 1)都只是把状态设为1,计数器永远不会增长。而createSignal返回的getter函数能随时获取最新状态,刚好能避开这类问题。以下是具体实现方案:

核心实现代码

利用useRef存储可变状态(不会触发重渲染),搭配一个空的useState触发组件更新,同时封装get和set方法对外暴露:

import { useRef, useState, useCallback } from 'react';

function createSignal(initialValue) {
  // 用useRef保存状态,保证值可变且能随时获取最新值
  const valueRef = useRef(initialValue);
  // 空状态用于触发组件重渲染,每次更新生成新对象即可触发
  const [, triggerRender] = useState({});

  // 获取最新状态的getter
  const get = useCallback(() => valueRef.current, []);

  // 更新状态的setter,支持函数式更新
  const set = useCallback((newValue) => {
    const finalValue = typeof newValue === 'function' 
      ? newValue(valueRef.current) 
      : newValue;
    
    if (finalValue !== valueRef.current) {
      valueRef.current = finalValue;
      // 触发组件重渲染
      triggerRender({});
    }
  }, []);

  return [get, set];
}

修复后的AutoCounter组件

用实现好的createSignal替换useState,即可解决闭包问题:

function AutoCounter() {
  const [getCount, setCount] = createSignal(0);

  useEffect(() => {
    const timer = setInterval(() => {
      // 支持函数式更新,或直接调用getCount()获取最新值
      setCount(prev => prev + 1);
    }, 500);

    return () => clearInterval(timer);
  }, []);

  return <div>counter: {getCount()}</div>;
}

方案原理说明

  • useRef的.current属性是可变的,不受组件渲染周期限制,get()方法每次都能拿到最新状态,不会被闭包捕获旧值。
  • 用空对象触发重渲染,既避免了额外状态的干扰,又能保证状态更新后组件及时刷新。
  • useCallback包裹get和set,让它们的引用保持稳定,不会因组件重渲染而变化,减少不必要的依赖更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 00:26:02