У меня есть хук API под названием useAPICall
, который имеет обратный вызов call
. Этот обратный вызов проверяет, не истек ли токен, хранящийся в реагирующей переменной с именем auth
, обновляет его при необходимости, затем вызывает функцию извлечения.
Я вызываю его в моем компоненте так:
const [api] = useAPICall();
useEffect(() => {
api.call('/api/settings/mine/').then(data => {
// do stuff here
});
}, []);
И это работает. Он проходит поток аутентификации и вызывает API. Но если у меня useAPICall
есть несколько компонентов, которые все пытаются вызвать API примерно в одно и то же время (например, загрузка холодной страницы), то каждый его экземпляр вызывает метод токена refre sh, потому что срок его действия истек.
Информация об аутентификации (access / refre sh токены) хранится в реагирующей глобальной переменной 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]
}
Как я могу предотвратить их запустить метод refre sh несколько раз?
Если есть лучший способ (без избыточности) иметь универсальный поток API (где любой вызов API сначала проверяет токен доступа и при необходимости обновляет sh), тогда я готов выслушать.