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

React组件中状态未更新仍为默认值的原因及解决方法求助

React 回调函数中 useState 状态始终显示初始值的问题

问题描述

在Users组件中,通过useState声明了userData状态,组件内的console.log('user Data:', userData)能正确显示更新后的数值,但在onAddingNewUser回调函数中,console.log('EmaiL:', email, userData)却始终显示默认的空数组。

组件代码如下:

const Users = () => {
    const { rightSideBarState, setRightSideBarState } = React.useContext(RightSidebarContext);
    const { setHeaderState } = React.useContext(HeaderContext);
    const [active, setActive] = React.useState<string | null>(null);
    const [searchText, setSearchText] = React.useState<string>('');
    const [userData, setUserData] = React.useState<User.UserData[]>([]);

    console.log('user Data:', userData);

    const onAddingNewUser = async (services: User.SucessfulInvitationSent[], email: string) => {
        console.log('EmaiL:', email, userData);
  
    };

    const { refetch } =
        useQuery([`users`], () => getUsersData(searchText).then((data) => setUserData(data)), {
            suspense: true,
        }) ?? [];

    const onAddUserClicked = () => {
        setRightSideBarState({
            visible: true,
            rightSidebarDisplay: {
                headerTitle: 'Add Users',
                headerCloseAction: () => {
                    setRightSideBarState({ visible: false });
                    setActive('');
                },
                content: <RightSidebarCreateUser onAddingNewUser={onAddingNewUser} />,
            },
        });
    };
}

问题成因

这是典型的React闭包陷阱:

  1. 组件初始渲染时,onAddingNewUser函数被创建,此时它捕获了当前作用域下的userData(空数组)。
  2. 当userData通过useQuery更新后,组件会重新渲染并创建新的onAddingNewUser函数,但此时RightSidebarCreateUser组件已经挂载,它接收的还是初始渲染时传递的旧版onAddingNewUser,所以回调里始终访问的是初始的空数组。
  3. 另外,当前使用useQuery的方式不规范:直接在查询函数里调用setUserData,不符合useQuery的设计逻辑,容易引发状态同步问题。

解决方法

方法1:使用useRef保存最新状态引用

useRef的.current属性可以随时更新且不会触发组件重渲染,回调函数中可直接访问最新状态值:

const Users = () => {
    // ...其他状态
    const [userData, setUserData] = React.useState<User.UserData[]>([]);
    // 声明ref保存最新userData
    const userDataRef = React.useRef<User.UserData[]>([]);

    // 同步更新ref
    React.useEffect(() => {
        userDataRef.current = userData;
    }, [userData]);

    const onAddingNewUser = async (services: User.SucessfulInvitationSent[], email: string) => {
        // 访问ref的current属性获取最新值
        console.log('EmaiL:', email, userDataRef.current);
    };

    // ...其他代码
}

方法2:用useCallback包裹回调并添加依赖

通过useCallback让onAddingNewUser在userData变化时重新创建,同时确保打开侧边栏时传递最新的回调函数:

const Users = () => {
    // ...其他状态
    const [userData, setUserData] = React.useState<User.UserData[]>([]);

    // 用useCallback包裹,依赖userData
    const onAddingNewUser = React.useCallback(async (services: User.SucessfulInvitationSent[], email: string) => {
        console.log('EmaiL:', email, userData);
    }, [userData]);

    // 同样用useCallback包裹打开侧边栏的函数,依赖最新的onAddingNewUser
    const onAddUserClicked = React.useCallback(() => {
        setRightSideBarState({
            visible: true,
            rightSidebarDisplay: {
                headerTitle: 'Add Users',
                headerCloseAction: () => {
                    setRightSideBarState({ visible: false });
                    setActive('');
                },
                content: <RightSidebarCreateUser onAddingNewUser={onAddingNewUser} />,
            },
        });
    }, [setRightSideBarState, setActive, onAddingNewUser]);

    // 修正useQuery的使用方式:直接返回数据,再同步到state
    const { data: usersData, refetch } = useQuery(
        ['users', searchText], // 添加searchText作为查询依赖
        () => getUsersData(searchText),
        { suspense: true }
    );

    React.useEffect(() => {
        if (usersData) {
            setUserData(usersData);
        }
    }, [usersData]);

    // ...其他代码
}

方法3:直接使用useQuery返回的data(推荐)

如果不需要额外对userData做本地修改,完全可以跳过useState,直接使用useQuery返回的data,从根源避免状态同步问题:

const Users = () => {
    // ...其他状态
    // 去掉userData的useState,直接用useQuery的data
    const { data: userData, refetch } = useQuery(
        ['users', searchText],
        () => getUsersData(searchText),
        { suspense: true }
    );

    const onAddingNewUser = React.useCallback(async (services: User.SucessfulInvitationSent[], email: string) => {
        console.log('EmaiL:', email, userData);
    }, [userData]);

    // ...其他代码
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 17:33:16