React Router页面刷新/直接访问时请求401问题求助
问题
开发模拟黑胶店的React应用时,「历史订单」功能出现异常:
- 从应用内部跳转至订单页面时,接口调用正常,认证通过,数据渲染正确;
- 刷新页面或直接在地址栏输入订单页面URL时,触发401认证错误,日志显示
useEffect在token获取完成前就发起了请求,后续虽拿到正确响应,但应用已崩溃。
相关代码:
import { useContext, useEffect, useState } from 'react' import AuthContext from '../context/AuthContextProvider'; import { fetchAllOrders } from '../api/api'; import OrderDetails from './OrderDetails'; export const Orders = () => { const authCtx = useContext(AuthContext); const token = authCtx.loggedInUserData.auth_token const [orders, setOrders] = useState({}); useEffect(() => { async function getAllOrders() { console.log("effect ran", token) const response = await fetchAllOrders(token); console.log(response) setOrders(response); // setOrders(response.data); // when using axios } getAllOrders(); }, [token]); console.log(orders) return ( <main> {orders.length > 0 && { token } && <div> {orders.map(order => <OrderDetails key={order.id} order={order} /> )} </div> } </main> ) }
原因分析
- 场景渲染时机差异
- 内部跳转:应用已处于运行状态,AuthContext中的token早已初始化完成,组件挂载时能直接拿到有效token,
useEffect触发时请求携带的是有效认证信息。 - 刷新/直接访问:页面重新加载,React应用从头初始化,AuthContext的token(通常从localStorage/cookie读取)需要异步读取或初始化,组件挂载时token还未准备好(可能为
undefined或空值),导致fetchAllOrders请求携带无效token,触发401错误。
- 内部跳转:应用已处于运行状态,AuthContext中的token早已初始化完成,组件挂载时能直接拿到有效token,
- 组件状态与渲染逻辑漏洞
- 初始
orders设为{},后续即使拿到正确响应,orders.length判断会出错(对象没有length属性),导致渲染逻辑异常,引发应用崩溃。 - 代码中
{ token }的判断毫无意义,它永远是一个包含token属性的对象(真值),无法起到拦截无token时渲染的作用。
- 初始
解决方向
1. 拦截无效请求,避免无token时调用接口
在useEffect中先判断token是否有效,只有存在有效token时才发起请求:
useEffect(() => { async function getAllOrders() { if (!token) return; // 无有效token时直接返回,不发起请求 const response = await fetchAllOrders(token); setOrders(response); } getAllOrders(); }, [token]);
2. 修正订单状态与渲染逻辑
- 将
orders初始状态设为数组[],符合订单列表的数据结构:const [orders, setOrders] = useState([]); - 优化渲染条件,去掉无效判断,增加友好提示:
return ( <main> {token && orders.length > 0 && ( <div> {orders.map(order => <OrderDetails key={order.id} order={order} /> )} </div> )} {token && orders.length === 0 && <p>暂无历史订单</p>} {!token && <p>请登录后查看订单</p>} </main> )
3. 优化AuthContext的token初始化逻辑
确保AuthContext在应用初始化时优先完成token读取,或者提供加载状态,让订单组件等待token准备完成后再渲染:
// AuthContextProvider示例 const AuthContextProvider = ({ children }) => { const [loggedInUserData, setLoggedInUserData] = useState(null); const [isLoading, setIsLoading] = useState(true); useEffect(() => { // 从localStorage读取保存的用户数据 const savedData = localStorage.getItem('userData'); if (savedData) { setLoggedInUserData(JSON.parse(savedData)); } setIsLoading(false); }, []); return ( <AuthContext.Provider value={{ loggedInUserData, isLoading }}> {!isLoading && children} </AuthContext.Provider> ) }
这样订单组件会在token初始化完成后才挂载,从根源避免无token时发起请求。
内容的提问来源于stack exchange,提问作者karalkal
相关产品推荐
相关产品推荐

