如何在React的非组件普通类中使用Context获取存储的鉴权token
核心问题说明
- 你当前的
AuthContextProvider仅向Context注入了isAuthenticated和toggleAuth两个值,userToken、userId等字段根本没有对外暴露,就算是React组件也无法从Context中读取到这些值。 static contextType是React专门为React类组件提供的Context读取能力,你写的MediaService是普通JS类,不属于React组件体系,自然不具备读取Context的能力,this.context必然是undefined。
第一步:先修复AuthContext配置
首先修正Context的对外暴露字段,否则后续所有读取操作都会失效:
import React, { useState, createContext, useEffect } from 'react'; import loginService from '../service/LoginService'; import axios from 'axios'; export const AuthContext = createContext(); const AuthContextProvider = (props) => { const [isAuthenticated, setIsAuthenticated] = useState(false); const [userToken, setUserToken] = useState(""); const [userId, setUserId] = useState(""); const [userName, setUserName] = useState(""); const toggleAuth = () => { if (!isAuthenticated) { setUserToken(loginService.getUserToken()); setUserId(loginService.getUserId()); setUserName(loginService.getUserName()); setIsAuthenticated(true); } else { setUserToken(null); setUserId(null); setUserName(null); setIsAuthenticated(false); } } // 补充缺失的暴露字段 return ( <AuthContext.Provider value={{ isAuthenticated, toggleAuth, userToken, userId, userName }}> {props.children} </AuthContext.Provider> ); } export default AuthContextProvider;
第二步:根据需求选择解耦方案
以下两种方案都可以实现MediaService和React组件体系的解耦,按需选择即可:
方案1:参数透传(彻底解耦,推荐)
该方案下MediaService完全不需要感知React、Context的存在,所有依赖参数从外部传入,可复用性最高。
- 修改
MediaService代码:
import axios from 'axios'; class MediaService { galleryItems = []; constructor() { this.galleryItems = []; } // 新增token入参,注意原代码的Bearer拼写错误,不是Barier addItem = (item, token) => { axios.post("http://localhost:8080/image", item, { headers: { "Authorization": `Bearer ${token}` } }) .then((response) => { item.id = response.data.id; this.galleryItems.push(item); }).catch((err) => { console.error(err); }); } } export default new MediaService(); // 导出单例直接使用
- 组件内调用方式:
import { useContext } from 'react'; import { AuthContext } from '你的AuthContext路径'; import mediaService from '你的MediaService路径'; function GalleryComponent() { // 仅在调用方组件读取Context const { userToken } = useContext(AuthContext); const handleUpload = (item) => { // 调用时透传token即可 mediaService.addItem(item, userToken); } // 其余组件逻辑省略 }
方案2:Axios全局拦截器自动注入Token
适合项目请求量较大,不想每个方法都重复传token的场景
- 在
AuthContextProvider中新增token监听逻辑,更新axios全局配置:
// 在AuthContextProvider中补充useEffect逻辑 const AuthContextProvider = (props) => { // 原有state、toggleAuth逻辑不变 // 新增:监听token变化,自动更新全局请求头 useEffect(() => { if (userToken) { axios.defaults.headers.common['Authorization'] = `Bearer ${userToken}`; } else { delete axios.defaults.headers.common['Authorization']; } }, [userToken]) // 原有return逻辑不变 }
- 此时
MediaService完全不需要处理token相关逻辑:
class MediaService { galleryItems = []; constructor() { this.galleryItems = []; } addItem = (item) => { // 不需要手动加headers,axios会自动携带全局配置的token axios.post("http://localhost:8080/image", item) .then((response) => { item.id = response.data.id; this.galleryItems.push(item); }).catch((err) => { console.error(err); }); } }
内容的提问来源于stack exchange,提问作者Olga
相关产品推荐
相关产品推荐

