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

React useState调用set方法后状态未立即更新问题排查

问题根因
  • React函数组件的state属于对应渲染周期的闭包常量:调用setState不会修改当前执行上下文中已有的state变量,只会调度一次组件重渲染,新的state值只会在下一次渲染生成的闭包中生效。因此在setAccessKeys调用后立刻打印当前作用域的accessKeys,拿到的永远是本次渲染的旧值,不可能是刚设置的新值。
  • 你的useEffect依赖配置错误:依赖数组中加入了accessKeys,会触发无限执行循环——effect内修改accessKeys触发重渲染,重渲染后因accessKeys变化再次触发effect执行,再次发起请求、修改state,这就是你观察到组件多次重复渲染的直接原因。
  • 现有set逻辑使用追加写法[...prevKeys, ...data]配合错误的依赖,还会导致每次effect执行都重复往数组里追加接口返回的数据,最终出现数据重复冗余。
修复方案
  1. 移除useEffect依赖数组中的accessKeys,数据拉取逻辑仅在组件挂载时执行一次即可,不需要随accessKeys变化重复触发
  2. 首次拉取全量数据时直接用接口返回值替换初始state即可,不需要基于prev追加,避免数据重复
  3. 不要在setState的同步调用后立刻读取当前作用域的旧state值,要观察最新state可以直接在组件顶层打印,或单独写监听accessKeys变化的useEffect。

修复后的完整代码:

import { useState, useEffect } from "react";
import axios from "axios";
import AccessKey from "./AccessKey";
import { toast } from "react-toastify";
import { useNavigate } from "react-router-dom";
import "./AccessKey.module.css";

const AccessKeys = () => {
  const [accessKeys, setAccessKeys] = useState([]);
  const navigate = useNavigate();

  useEffect(() => {
    const getAccessKeys = async () => {
      try {
        const token = localStorage.getItem("auth");
        const response = await axios.get(
          "http://localhost:5000/api/keys/user",
          {
            headers: {
              authorization: `Bearer ${token}`,
            },
          }
        );
        const data = response.data;
        // 首次拉取直接替换初始值即可
        setAccessKeys(data);
      } catch (error) {
        navigate("/");
        toast.error(error.response.data.message);
      }
    };

    getAccessKeys();
    // navigate是路由返回的稳定引用,不会触发重复执行
  }, [navigate]);

  // 组件顶层打印可以拿到每次渲染对应的最新state
  console.log(accessKeys);

  return (
    <>
      {accessKeys.length > 0 ? (
        <main>
          {accessKeys.map((accessKey) => (
            <AccessKey key={accessKey._id} acesskey={accessKey} />
          ))}
        </main>
      ) : (
        <h4>You do not have any Access Keys at the moment</h4>
      )}
    </>
  );
};

export default AccessKeys;

修复后渲染流程说明:

  1. 首次渲染:accessKeys为初始空数组,展示空状态提示,同时触发useEffect执行接口请求
  2. 接口返回后调用setAccessKeys调度重渲染,第二次渲染时accessKeys即为接口返回的全量数据,正常渲染列表
  3. 因依赖中没有accessKeys,effect不会重复执行,不会产生多余渲染和重复请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 15:27:15