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

如何在非函数组件的LoginRequest中使用React Hooks(useDispatch)?

问题分析

核心业务函数LoginRequest直接调用useDispatch违反React Hooks规则(Hooks仅允许在函数组件或自定义Hooks的顶层调用),该函数被APP多处依赖,需要调整Token存储逻辑,同时可结合axios拦截器实现Token的自动管理。

解决方案

方案1:传入dispatch参数(最小改动)

直接将dispatch作为参数传入LoginRequest,避免在非组件/非自定义Hooks中调用Hooks:

修改后的LoginRequest:

export async function LoginRequest(chiperText, dispatch) { // 新增dispatch参数
  try {
    let loginRequest = await fetch(baseUrl + "/Login", {
      method: "post",
      body: JSON.stringify({ chiperText }),
      headers: {
        "Content-Type": "application/json-patch+json",
        Accept: "application/json",
      },
    });

    let jwtToken = await loginRequest.json();
    dispatch(setJwtToken(jwtToken)); // 使用传入的dispatch
    return jwtToken;
  } catch (error) {
    console.error(error);
    return null;
  }
}

在调用的函数组件中使用:

import { useDispatch } from 'react-redux';
import { LoginRequest, GetLoginChiperText } from './你的文件路径';

function LoginScreen() {
  const dispatch = useDispatch();

  const handleLogin = async () => {
    const chiperText = GetLoginChiperText({/* 传入参数 */});
    const token = await LoginRequest(chiperText, dispatch);
    // 后续业务逻辑
  };

  return <>{/* 组件内容 */}</>;
}

方案2:直接使用Redux Store实例

在Redux Store配置文件中导出Store实例,工具函数直接调用store.dispatch:

  1. 配置Store并导出(示例store.js):
import { createStore } from 'redux';
import rootReducer from './reducers';

export const store = createStore(rootReducer); // 导出Store实例
  1. 修改LoginRequest:
// 导入Store实例
import { store } from '../store'; // 路径根据实际项目调整
import { setJwtToken } from "../actions/jwtTokenActions";

export async function LoginRequest(chiperText) {
  try {
    let loginRequest = await fetch(baseUrl + "/Login", {
      method: "post",
      body: JSON.stringify({ chiperText }),
      headers: {
        "Content-Type": "application/json-patch+json",
        Accept: "application/json",
      },
    });

    let jwtToken = await loginRequest.json();
    store.dispatch(setJwtToken(jwtToken)); // 直接调用Store的dispatch
    return jwtToken;
  } catch (error) {
    console.error(error);
    return null;
  }
}

方案3:结合Axios拦截器自动管理Token(推荐)

通过axios拦截器统一处理请求头的Token携带、Token过期重试等场景,同时整合Token存储逻辑:

步骤1:创建Axios实例并配置拦截器

新建apiClient.js文件:

import axios from 'axios';
import Constants from "expo-constants";
import { store } from '../store';
import { setJwtToken } from "../actions/jwtTokenActions";

const baseUrl = Constants.manifest.configurations.baseUrl;
// 创建axios实例
const apiClient = axios.create({
  baseURL: baseUrl,
  headers: {
    "Content-Type": "application/json-patch+json",
    Accept: "application/json",
  },
});

// 请求拦截器:自动为请求添加Authorization头
apiClient.interceptors.request.use(
  (config) => {
    const state = store.getState();
    const jwtToken = state.jwtToken; // 对应Redux中存储Token的字段
    if (jwtToken) {
      config.headers.Authorization = `Bearer ${jwtToken}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// 响应拦截器:处理Token过期等异常(可选)
apiClient.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config;
    // 假设后端返回401代表Token过期
    if (error.response.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true;
      // 此处可添加Token刷新逻辑,示例:
      // const newToken = await refreshToken();
      // store.dispatch(setJwtToken(newToken));
      // originalRequest.headers.Authorization = `Bearer ${newToken}`;
      // return apiClient(originalRequest);
    }
    return Promise.reject(error);
  }
);

export default apiClient;

步骤2:修改业务函数使用Axios实例

import apiClient from './apiClient';
import { store } from '../store';
import { setJwtToken } from "../actions/jwtTokenActions";

export async function LoginRequest(chiperText) {
  try {
    const { data: jwtToken } = await apiClient.post("/api/Login/Login", { chiperText });
    store.dispatch(setJwtToken(jwtToken));
    return jwtToken;
  } catch (error) {
    console.error(error);
    return null;
  }
}

// 简化CheckJwtToken函数
export async function CheckJwtToken() {
  try {
    await apiClient.get("/api/Login/CheckJwtToken");
    return true;
  } catch (error) {
    console.log(error)
    return false;
  }
}

步骤3:修复GetLoginChiperText的变量错误

原函数中误用body变量,替换为参数params:

export function GetLoginChiperText(params) {
  params.time = getCurrentUtcDate().getTime();

  var key = enc.Utf8.parse(secretKey);
  var iv = enc.Utf8.parse(secretKey);

  var chiperText = AES.encrypt(enc.Utf8.parse(JSON.stringify(params)), key, {
    keySize: 128 / 8,
    iv: iv,
    mode: mode.CBC,
    padding: pad.Pkcs7,
  }).toString();
  return chiperText;
}
方案选择
  • 快速修复现有问题选方案1,改动最小;
  • 希望工具函数直接操作Redux选方案2;
  • 长期维护、统一管理API请求选方案3,便于后续扩展Token刷新、请求重试等功能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 06:18:10