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

React回调函数无法读取最新useState状态的问题及替代方案

问题原因

你遇到的是闭包陷阱:

  • 你的useEffect依赖是空数组[],只会在组件首次挂载时执行一次。
  • 此时refreshWarehouseCallback作为订阅回调被传入,它会捕获这个挂载时刻的myState快照。
  • 后续myState更新时,组件会重新渲染,但旧的订阅回调仍然保留着对初始myState的引用,自然读不到最新值。
  • 并不是useState和回调不兼容,而是订阅回调的闭包没有捕获到更新后的state。
不使用useRef的解决方案

方案1:将回调移入useEffect,添加myState到依赖

每次myState更新时,取消旧订阅并重新订阅,让新回调捕获最新的state:

export function Schedules({ tsmService, push, pubsub }: Props) {
    const [myState, setMyState] = useState<any>(initialState);

    useEffect(() => {
        service
            .getWarehouses()
            .then((warehouses) => getCurrentWarehouseData(warehouses))
            .catch(() => catchError());

        // 把回调写在useEffect内部,直接捕获当前的myState
        function refreshWarehouseCallback(eventName: string, content: any) {
            const { warehouseId } = myState; // 现在能拿到最新值了
            switch(eventName) {
                case pushEvents.ramp.updated: {
                    // 处理逻辑
                    break;
                }
            }
        }

        const pushToken = push.subscribe('public/ttt/#');
        const pubSubToken = pubsub.subscribe('push:ttt.*', refreshWarehouseCallback);

        return () => {
            pubsub.unsubscribe(pubSubToken);
            push.unsubscribe(pushToken);
        };
    }, [myState]); // 添加myState到依赖,每次state更新重新执行effect

    // ...其他代码
}

方案2:用useCallback包裹回调,配合useEffect依赖

如果回调需要在多个地方复用,可以用useCallback缓存回调,确保每次state更新时回调能拿到最新值:

export function Schedules({ tsmService, push, pubsub }: Props) {
    const [myState, setMyState] = useState<any>(initialState);

    // 用useCallback包裹,依赖myState,每次state更新生成新的回调
    const refreshWarehouseCallback = useCallback((eventName: string, content: any) => {
        const { warehouseId } = myState; // 最新state
        switch(eventName) {
            case pushEvents.ramp.updated: {
                // 处理逻辑
                break;
            }
        }
    }, [myState]);

    useEffect(() => {
        service
            .getWarehouses()
            .then((warehouses) => getCurrentWarehouseData(warehouses))
            .catch(() => catchError());

        const pushToken = push.subscribe('public/ttt/#');
        const pubSubToken = pubsub.subscribe('push:ttt.*', refreshWarehouseCallback);

        return () => {
            pubsub.unsubscribe(pubSubToken);
            push.unsubscribe(pushToken);
        };
    }, [refreshWarehouseCallback]); // 依赖回调,回调更新时重新订阅

    // ...其他代码
}

注意事项

  • 两种方案都会在myState更新时重新订阅,要确保你的pubsub和push的取消/重新订阅逻辑没有副作用。
  • 如果myState更新频繁,可能会导致多次订阅/取消,这时可以考虑合并state更新来减少触发次数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 21:31:07