如何确保Fetch请求前Cookie已就绪?解决首次渲染数据获取失败问题
解决方案
方法一:合并请求逻辑,确保Cookie设置后再获取数据
把获取令牌和数据的逻辑放在同一个useEffect里,通过链式调用让数据请求等待Cookie设置完成后再执行:
import Cookies from 'js-cookie'; const [isLoading, setLoading] = useState(false) const [data, setData] = useState(null) useEffect(() => { setLoading(true) fetch('/api/token') .then((res) => res.json()) .then((tokenData) => { Cookies.set("TOKEN", tokenData.access_token); // 令牌写入Cookie后立刻发起数据请求 return fetch('/api/data'); }) .then((res) => res.json()) .then((data) => { setData(data); setLoading(false); }) .catch((err) => { // 请求失败时重置加载状态 setLoading(false); console.error('请求出错:', err); }); }, [])
方法二:用状态变量跟踪令牌状态,触发数据获取
新增一个状态变量标记令牌是否设置完成,数据请求的useEffect依赖这个状态,只有当令牌就绪后才执行:
import Cookies from 'js-cookie'; const [isLoading, setLoading] = useState(false) const [data, setData] = useState(null) const [tokenReady, setTokenReady] = useState(false); // 专门负责获取并设置令牌 useEffect(() => { fetch('/api/token') .then((res) => res.json()) .then((tokenData) => { Cookies.set("TOKEN", tokenData.access_token); setTokenReady(true); // 标记令牌已写入Cookie }) .catch((err) => { console.error('获取令牌失败:', err); }); }, []) // 令牌就绪后才请求数据 useEffect(() => { if (!tokenReady) return; setLoading(true) fetch('/api/data') .then((res) => res.json()) .then((data) => { setData(data); setLoading(false); }) .catch((err) => { setLoading(false); console.error('获取数据失败:', err); }); }, [tokenReady])
方法三:跳过Cookie,直接传递令牌(可选优化)
如果不需要把令牌持久化到客户端Cookie,可直接在获取令牌后通过请求头传给数据接口,彻底避开Cookie的时机问题:
const [isLoading, setLoading] = useState(false) const [data, setData] = useState(null) useEffect(() => { setLoading(true) fetch('/api/token') .then((res) => res.json()) .then((tokenData) => { // 直接把令牌通过请求头传给数据接口 return fetch('/api/data', { headers: { 'Authorization': `Bearer ${tokenData.access_token}` } }); }) .then((res) => res.json()) .then((data) => { setData(data); setLoading(false); }) .catch((err) => { setLoading(false); console.error('请求出错:', err); }); }, [])
同时修改/api/data.js,优先从请求头读取令牌:
export default async function handler(req, res) { // 先从请求头取令牌,没有再读Cookie const authHeader = req.headers.authorization; const token = authHeader ? authHeader.split(' ')[1] : req.cookies['TOKEN']; if (token){ const result = await fetch(`url`, { headers: { accept: 'application/json', Authorization: `Bearer ${token}`, } }); const data = await result.json() res.status(200).json(data) } else { res.status(401).json({ message: '未提供访问令牌' }); } }
额外提示
- 所有请求都要加错误处理,避免加载状态一直卡在
true; - 如果需要持久化令牌,设置Cookie时可以加上过期时间:
Cookies.set("TOKEN", tokenData.access_token, { expires: 7 }),这样下次访问时Cookie已存在,不会再出现首次加载问题。
内容的提问来源于stack exchange,提问作者greendalf
相关产品推荐
相关产品推荐

