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

React函数组件中EventSource回调内State无法更新的问题求助

解决React EventSource回调中无法获取最新状态的问题

你判断的没错,这确实是闭包导致的问题:useEffect依赖数组为空,只会在组件挂载时执行一次,此时创建的updateRooms函数捕获的是初始的rooms空数组。后续setRooms更新状态后,旧的updateRooms并不会重新生成,所以回调里始终拿不到更新后的状态。

下面提供两种实用的解决方法:

方法一:使用setState的函数式更新

React的setState支持传入函数,该函数会接收当前最新的状态值作为参数,完全绕开闭包的限制。直接在这个函数里处理状态更新逻辑即可:

function HomePage() {
    const [rooms, setRooms] = useState<Room[]>([]);

    const getRooms = async () => {
        const data = await RoomService.getAll(currentPage);
        setRooms(data.rooms);
    }

    const updateRooms = (data: AddRoomPayload | DeleteRoomPayload) => {
        setRooms(prevRooms => {
            // prevRooms就是当前最新的房间列表
            console.log(prevRooms);
            
            // 根据事件类型处理房间添加/删除
            if ('room' in data) {
                return [...prevRooms, data.room];
            } else if ('roomId' in data) {
                return prevRooms.filter(room => room.id !== data.roomId);
            }
            return prevRooms;
        });
    }

    useEffect(() => {
        getRooms();

        const url = new URL(process.env.REACT_APP_SSE_BASE_URL ?? '');
        url.searchParams.append('topic', '/room');
        const eventSource = new EventSource(url);
        eventSource.onmessage = e => updateRooms(JSON.parse(e.data));

        // 组件卸载时关闭EventSource,避免内存泄漏
        return () => eventSource.close();
    }, [])

    ...
}

方法二:用useRef保存最新状态

如果你的业务逻辑需要先读取最新状态做额外处理,再更新状态,可以用useRef来实时同步最新的rooms值:

function HomePage() {
    const [rooms, setRooms] = useState<Room[]>([]);
    // 用ref保存最新的rooms状态
    const roomsRef = useRef<Room[]>([]);

    // 每次rooms更新时同步ref的值
    useEffect(() => {
        roomsRef.current = rooms;
    }, [rooms]);

    const getRooms = async () => {
        const data = await RoomService.getAll(currentPage);
        setRooms(data.rooms);
    }

    const updateRooms = (data: AddRoomPayload | DeleteRoomPayload) => {
        // 从ref获取最新状态
        const latestRooms = roomsRef.current;
        console.log(latestRooms);
        
        let newRooms = latestRooms;
        if ('room' in data) {
            newRooms = [...latestRooms, data.room];
        } else if ('roomId' in data) {
            newRooms = latestRooms.filter(room => room.id !== data.roomId);
        }
        
        setRooms(newRooms);
    }

    useEffect(() => {
        getRooms();

        const url = new URL(process.env.REACT_APP_SSE_BASE_URL ?? '');
        url.searchParams.append('topic', '/room');
        const eventSource = new EventSource(url);
        eventSource.onmessage = e => updateRooms(JSON.parse(e.data));

        return () => eventSource.close();
    }, [])

    ...
}

额外注意

不要忘记在useEffect的返回函数里关闭EventSource,否则组件卸载后SSE连接会一直存在,造成内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 22:15:38