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

React函数式组件中如何在函数内访问更新后的state?

问题原因

你的问题出在闭包陷阱上:useEffect的依赖项是空数组[],这意味着它只在组件挂载时执行一次。此时readNum回调捕获的是初始状态的num(值为0),后续num通过setNum更新后,这个回调不会重新创建,所以始终读取的是最初的闭包值。

解决方案

方法1:用useRef保存最新的num值

通过useRef维护一个始终指向最新num的引用,事件回调里直接读取这个引用就能拿到最新值:

import {useEffect, useRef, useState} from "react";
import {EventEmitter} from "events";

const NumComponent = () => {
    const [num, setNum] = useState(0)
    const numRef = useRef(num);
    
    // 每次num更新时同步更新ref的内容
    useEffect(() => {
        numRef.current = num;
    }, [num]);

    const emitter = new EventEmitter()
    const emitterRef = useRef(emitter)

    useEffect(() => {
        emitterRef.current.on('setNum', () => setNum(10))
        // 读取ref里的最新num
        emitterRef.current.on('readNum', () => console.log(numRef.current))
    }, [])

    return <div>
        {num}
        <div>
            <button onClick={() => emitterRef.current.emit('setNum')}>set num</button>
        </div>

        <div>
            <button onClick={() => emitterRef.current.emit('readNum')}>read num</button>
        </div>
    </div>
}
export default NumComponent

方法2:更新useEffect的依赖项

把num加入useEffect的依赖数组,这样每次num变化时,都会重新绑定事件回调,确保回调能获取最新的num。注意要添加清理函数移除旧监听,避免内存泄漏:

import {useEffect, useRef, useState} from "react";
import {EventEmitter} from "events";

const NumComponent = () => {
    const [num, setNum] = useState(0)
    const emitter = new EventEmitter()
    const emitterRef = useRef(emitter)

    useEffect(() => {
        const handleSetNum = () => setNum(10);
        const handleReadNum = () => console.log(num);
        
        emitterRef.current.on('setNum', handleSetNum)
        emitterRef.current.on('readNum', handleReadNum)
        
        // 组件更新或卸载时移除旧监听
        return () => {
            emitterRef.current.off('setNum', handleSetNum)
            emitterRef.current.off('readNum', handleReadNum)
        }
    }, [num]) // 依赖num,更新时重新绑定回调

    return <div>
        {num}
        <div>
            <button onClick={() => emitterRef.current.emit('setNum')}>set num</button>
        </div>

        <div>
            <button onClick={() => emitterRef.current.emit('readNum')}>read num</button>
        </div>
    </div>
}
export default NumComponent

方法3:函数式更新获取最新值(适用于需要修改num的场景)

如果你的readNum回调不仅要读取还要修改num,可以用setNum的函数式形式,它能直接拿到当前最新的状态值:

// 示例:readNum时打印最新num并加1
emitterRef.current.on('readNum', () => {
    setNum(prevNum => {
        console.log(prevNum); // 这里能拿到最新的num值
        return prevNum + 1;
    })
})
总结

单纯读取最新值选方法1或2都可以;如果要在回调里修改状态,方法3的函数式更新更直接。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 08:55:37