【发布时间】:2020-06-23 16:46:26
【问题描述】:
我有一个名为 useAPICall 的 API 挂钩,它有一个回调 call。此回调检查存储在名为 auth 的 reactn 变量中的令牌是否已过期,如有必要刷新它,然后调用 fetch 函数。
我在我的组件中这样称呼它:
const [api] = useAPICall();
useEffect(() => {
api.call('/api/settings/mine/').then(data => {
// do stuff here
});
}, []);
它确实有效。它通过身份验证流程并调用 API。但是如果我有 useAPICall 是多个组件都尝试在同一时间调用 API(例如冷页面加载),那么它的每个实例都会调用刷新令牌方法,因为它已过期。
身份验证信息(访问/刷新令牌)存储在 reactn 全局变量 auth 中,如下所示,在 useAPICall.js 挂钩内
import React, {useCallback, useContext, useEffect, useMemo, useState} from 'react';
import {useDispatch, useGlobal} from 'reactn';
export function useAPICall() {
const [auth, setAuth] = useGlobal('auth');
const authRefreshSuccess = useDispatch('authRefreshSuccess');
async function refreshToken() {
console.log('Refreshing access token...');
const authResponse = await fetch('/api/auth/token/refresh/', {
method: 'POST',
credentials: 'same-origin',
body: JSON.stringify({refresh: auth.refresh.token}),
headers: {
'Content-Type': 'application/json',
},
});
if (authResponse.ok) {
const authToken = await authResponse.json();
await authRefreshSuccess(authToken);
return authToken.access;
}
}
function isTokenExpired() {
if (localAuth.access)
return auth.access.exp <= Math.floor(Date.now() / 1000);
else
return false;
}
const call = useCallback(async (endpoint, options={headers: {}}) => {
console.log('performing api call');
token = undefined;
if (isTokenExpired())
token = await refreshToken();
else
token = localAuth.access.token;
const res = await fetch(endpoint, {
...options,
headers: {
...options.headers,
'Authorization': `Bearer ${token}`,
}
});
if (!res.ok)
throw await res.json();
return res.json();
}, []);
const anonCall = useCallback(async (endpoint, options={}}) => {
const res = await fetch(endpoint, options);
if (!res.ok)
throw await res.json();
return res.json();
}, []);
const api = useMemo(
() => ({
call,
anonCall,
}),
[call, anonCall,]
);
return [api]
}
如何防止他们多次触发刷新方法?
如果有更好的方法(不使用 redux)来获得通用 API 流(任何 API 调用都会首先检查访问令牌并在必要时刷新),那么我愿意倾听。
【问题讨论】: