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

useEffect中如何获取更新后的state值?打印users始终为初始空数组

问题原因

该问题是React钩子的闭包陷阱导致:
传入useEffect的空依赖数组表示这个副作用只会在组件首次渲染时执行1次,绑定的事件回调捕获的users变量永远是首次渲染时的初始值[],后续setUsers更新状态触发组件重渲染,也不会更新已经绑定好的事件回调里的闭包变量。


解决方案

方案1:用useRef存储最新状态(最推荐,不需要改动Pusher初始化逻辑)

用useRef作为容器存储最新的users值,ref的current属性是可变的,不会受闭包限制:

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

let [users, setUsers] = useState([]);
// 新增ref存储最新users
const usersRef = useRef(users);
// 监听users变化,同步更新ref
useEffect(() => {
  usersRef.current = users;
}, [users]);

useEffect(() => {
    axios.get('/chat_user_list').then((res) => {
        setUsers(res.data);
    });
    
    let pusher = new Pusher('api-key-over-here', {
        cluster: 'ap1',
        authEndpoint: "/admin/broadcasting/auth",
        auth: {
            headers: {
                "X-CSRF-Token": csrfToken,
                "Accept": "application/json"
            },
        },
    });
    let channel = pusher.subscribe(`presence-room`);

    channel.bind("pusher:member_added", (member) => {
        // 从ref中取最新的users
        console.log(usersRef.current);
        // 需要更新状态可以直接写为
        // setUsers([...usersRef.current, member.info])
    });
    
    // 组件卸载时清理连接避免内存泄漏
    return () => {
      channel.unbind("pusher:member_added");
      pusher.unsubscribe(`presence-room`);
      pusher.disconnect();
    }
}, []);

方案2:使用setState的函数式更新(仅适用于需要基于最新值更新状态的场景)

如果你在回调里只需要基于最新的users更新状态,不需要读取值做其他逻辑,可以直接用setState的函数式写法,回调参数自动拿到最新的前序状态:

channel.bind("pusher:member_added", (member) => {
  setUsers(prevUsers => {
    // prevUsers就是最新的users状态值
    console.log(prevUsers);
    return [...prevUsers, member.info];
  })
});

方案3:给useEffect添加依赖+清理逻辑

把users加入useEffect依赖数组,每次users变化时重新绑定事件,要注意加清理函数解绑旧事件避免重复绑定:

useEffect(() => {
    axios.get('/chat_user_list').then((res) => {
        setUsers(res.data);
    });
    
    let pusher = new Pusher('api-key-over-here', {
        cluster: 'ap1',
        authEndpoint: "/admin/broadcasting/auth",
        auth: {
            headers: {
                "X-CSRF-Token": csrfToken,
                "Accept": "application/json"
            },
        },
    });
    let channel = pusher.subscribe(`presence-room`);
    const handleMemberAdd = (member) => {
      console.log(users);
    }
    channel.bind("pusher:member_added", handleMemberAdd);
    
    // 每次重新执行副作用前先清理旧的连接和事件
    return () => {
      channel.unbind("pusher:member_added", handleMemberAdd);
      pusher.unsubscribe(`presence-room`);
      pusher.disconnect();
    }
}, [users]);

该方案不推荐,因为每次users变化都会重新初始化Pusher连接,会产生不必要的性能开销。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 06:27:02