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

如何遵守Hook规则封装适配useEffect的登录校验自定义Hook?

核心实现思路

自定义Hook仅在组件顶层调用,内部合法调用useHistory等内置Hook,将包含路由跳转、消息提示的副作用逻辑封装为普通函数返回,或者放到Hook内部的useEffect中执行,完全符合Hook调用规则。


方案1:返回校验函数(适配现有调用逻辑,改动最小)

自定义Hook代码

import { useHistory } from "react-router-dom";
// 若使用react-router v6,替换为useNavigate即可

function useLogin() {
  const history = useHistory();

  // 封装后的校验方法为普通函数,可在任意回调/useEffect中调用
  const checkLogin = (callback, redirectUrl = "/accounts/login", loginMessage) => {
    if (!state.user.authenticated) {
      history.push(redirectUrl);
      // 未传入自定义提示时调用默认提示
      loginMessage ? loginMessage() : teamhome2_message();
      return false;
    }
    callback?.();
    return true;
  };

  return { checkLogin };
}

组件内使用方式

// 组件顶层调用自定义Hook,符合Hook规则
const { checkLogin } = useLogin();

useEffect(() => {
  // 直接在useEffect中调用返回的普通校验函数即可
  checkLogin(() => {
    checkauth(() => {
      checkteamexists(teamname);
    })
  })
}, []);

方案2:自动校验登录(适合路由守卫场景)

如果校验逻辑是组件加载后自动执行,不需要手动控制时机,可以直接把校验逻辑放到Hook内部的useEffect中:

自定义Hook代码

import { useHistory, useEffect } from "react";

function useRequireLogin(isAuthenticated, redirectUrl = "/accounts/login", loginMessage) {
  const history = useHistory();

  useEffect(() => {
    if (!isAuthenticated) {
      history.push(redirectUrl);
      loginMessage ? loginMessage() : teamhome2_message();
    }
  }, [isAuthenticated, history, redirectUrl, loginMessage]);

  return isAuthenticated;
}

组件内使用方式

// 组件顶层调用,自动校验登录状态
const isLogin = useRequireLogin(state.user.is_authenticated);

useEffect(() => {
  // 登录状态有效再执行业务逻辑
  if (!isLogin) return;
  checkauth(() => {
    checkteamexists(teamname);
  })
}, [isLogin]);

原写法错误原因
  1. 原自定义Hook直接在渲染流程中执行history.push这种副作用操作,违反了React「渲染期间不能触发状态/路由更新」的规则,所以会抛出渲染期间更新的错误。
  2. 自定义Hook放到useEffect内调用会打乱Hook的固定调用顺序,违反Hook的基本使用规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.16 04:24:03