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

React函数式组件state变化时无法触发重渲染该如何解决?

问题根因
  • 负责拉取用户信息的useEffect依赖项为空数组,仅会在组件首次挂载时执行1次。用户首次登录前组件已经完成挂载,登录后回到页面不会重新触发接口请求,因此拿不到最新的用户信息。
  • 你将dataRes状态变化后的处理逻辑直接写在组件顶层渲染流程中,还在逻辑内直接调用setState,属于渲染期间更新状态的错误写法,不仅会触发不必要的重渲染,还可能出现状态更新不及时、逻辑不触发的问题。
  • 负责存储用户名的username状态被错误定义为布尔类型,和实际用户名做对比的判断逻辑永远不符合预期,导致登录状态更新失败。
  • 额外的1秒强制关闭loading的useEffect逻辑不合理,很容易出现接口还未返回就提前结束加载,导致登录状态还没更新就渲染出登录按钮的问题。
修复后代码
function Username() {
  const cookies = new Cookies();
  const [username, setUsername] = useState(null);
  const [loading, setLoading] = useState(true);
  const [shortened, setShortened] = useState(false);
  const authLink = "https://discord.com/api/oauth2/authorize?client_id=" + clientID + "&redirect_uri=" + clientRedirect + "&response_type=code&scope=identify%20guilds";
  const [loggedin, setLoggedin] = useState(false);
  const history = useHistory();
  const [data, setData] = useState(null);
  const userToken = cookies.get("someCookie");

  // 监听token变化,有token时自动拉取用户信息
  useEffect(() => {
    if (!userToken) {
      setLoading(false);
      return;
    }
    setLoading(true);
    fetch('SomeAPIUrlHere', {
      method: "POST",
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ token: userToken })
    })
    .then((res) => res.json())
    .then((data) => {
      setData(data);
      if (data?.username) {
        setUsername(data.username);
        setShortened(data.username.length > 10);
        setLoggedin(true);
      }
      setLoading(false);
    })
    .catch(err => {
      console.log(err);
      setLoading(false);
    })
  }, [userToken]);

  const SignOut = () => {
    cookies.remove("us_au_tok");
    history.push("/");
    window.location.reload(false);
  }

  return(
    <div className="flex float-left">
      <a href={loggedin === false ? authLink : "/dashboard"} className={loggedin === false ? "shadow-2xl text-center  text-white bg-gray rounded-2xl p-2 lg:px-5 md:px-5 sm:pl-3.5 xs:pl-3.5 mr-2 block lg:w-40 md:w-40" : "text-center text-white  rounded-2xl p-2 lg:px-5 md:px-5 sm:pl-3 xs:pl-3 mr-2 block lg:w-48 md:w-48"}>
        <div className={loading === true ? "md:w-8 lg:w-8 sm:w-7 xs:w-7 m-auto text-center" : "m-auto text-center"}>
          <div className="flex justify-nter">
            {loggedin === true ? <img src={`https://cdn.discordapp.com/avatars/${data.userid}/${data.avatar}.png?size=1024`} alt="Useravatar" className="lg:max-h-50 md:max-h-50 sm:max-h-35 xs:max-h-35 rounded-full mr-2"></img> : ""}
            {loading === true ? <img src={LoadingSVG} alt='Loading Animation'/> : <p className="hover:text-brightgray duration-300 lg:m-auto md:m-auto sm:my-auto xs:my-auto">{loggedin === true ? <span>{shortened === false ? username : username.substring(0, 10) + "..."}</span> : "Login"}</p> }
          </div>
        </div>
      </a>
      {loggedin === true ? <button onClick={SignOut}><FontAwesomeIcon icon={faSignOutAlt} className="text-white mr-4" title="Sign Out" /></button> : ""}
    </div>
  )
};
核心修改点
  • 给拉取用户信息的useEffect增加了userToken作为依赖项,登录后token生成/变化时会自动重新触发请求拉取用户信息,不需要手动刷新页面
  • 删除了顶层渲染流程中的状态更新逻辑,将用户信息处理全部挪到接口请求回调中,避免渲染期间更新状态的问题
  • 修复了username状态的类型错误,改为存储实际用户名字符串,逻辑判断符合预期
  • 移除了不合理的1秒强制关闭loading逻辑,loading状态完全由接口请求流程控制,不会出现接口未返回就结束加载的问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 12:45:04