Skip to content

Instantly share code, notes, and snippets.

@Lightnet
Last active March 8, 2022 19:42
Show Gist options
  • Save Lightnet/f2c571aa1f42eea6d55b619ed8fbd7ad to your computer and use it in GitHub Desktop.
Save Lightnet/f2c571aa1f42eea6d55b619ed8fbd7ad to your computer and use it in GitHub Desktop.
use Axios refresh Token API to reduce code repeat

use search engine to learn hook and axios for clean up and reuse.

Worked on refine the code to deal with the user interacting when type when render components.

Create the init instance when it mount.

Added isLoading to make sure the axios instance. One reason is that useEffect mount on when user doing get url on render to get data.

Watch variables and mount interceptors that check for the token expire. If events it will change in interceptors and clean up.

// https://stackoverflow.com/questions/38552003/how-to-decode-jwt-token-in-javascript-without-using-a-library
export function parseJwt(token) {
var base64Url = token.split('.')[1];
var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
var jsonPayload = decodeURIComponent(atob(base64).split('').map(function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
return JSON.parse(jsonPayload);
};
/*
LICENSE: MIT
Created by: Lightnet
*/
// https://stackoverflow.com/questions/59335963/react-hooks-display-global-spinner-using-axios-interceptor
import axios from "axios";
import { useEffect, useState } from "react";
import { parseJwt } from "../../lib/helper.mjs";
import { useAuth } from "../auth/AuthProvider";
export default function useAxiosTokenAPI(){
//const [tokenJWT, setTokenJWT] = useState();//can't use as return promise
const [tokenJWT, setTokenJWT] = useState({instance:null});
const [isLoading, setIsLoading] = useState(true);
const {
API_URL,
token, setToken,
expire, setExpire,
setStatus
} = useAuth();
//const instance = axios.create() // not here else when user typing it create same variable
function createInstance(){
//console.log("axios creating...")
const instance = axios.create({
baseURL: API_URL
//baseURL: "http://localhost:3000"
, headers: {
//'X-Custom-Header': 'foobar'
"Content-Type": "application/json"
}
});
return instance
}
// create config for request check
async function config(config){
const currentDate = new Date();
//console.log(expire)
if (expire * 1000 < currentDate.getTime()) {
//console.log("get update?")
const response = await axios.get('/token');
if(response.data.error){
//console.log("NOT LOGIN");
setStatus('unauth');
return config;
}
config.headers.Authorization = `Bearer ${response.data.accessToken}`;
setToken(response.data.accessToken);
const decoded = parseJwt(response.data.accessToken);
//setName(decoded.name);
setExpire(decoded.exp);
}else{
config.headers.Authorization = `Bearer ${token}`;
}
return config;
}
//create error event
function ErrorPromise(error){
return Promise.reject(error);
}
//init instance
useEffect(()=>{
setTokenJWT({instance:createInstance()})
},[])
//watch variable, init interceptors and clean up
useEffect(()=>{
//console.log(instance);
if(tokenJWT.instance!=null){
const configInterceptor=tokenJWT.instance.interceptors.request.use(config, ErrorPromise);
//console.log(configInterceptor);
setIsLoading(false);
return ()=>{
//console.log("clean up");
tokenJWT.instance?.interceptors.request.eject(configInterceptor);
setIsLoading(false);
}
}else{
setIsLoading(true);
}
},[tokenJWT.instance,token,expire]);//listen to three variables
return [tokenJWT,isLoading];
}
/*
// usage
const [axiosJWT, isLoading] = useAxiosTokenAPI();
useEffect(()=>{
console.log("axiosJWT init...");
console.log("isLoading: ", isLoading)
if((typeof axiosJWT?.instance=="function")&&(isLoading == false)){
console.log("GETTING...: ")
getPost();
}
},[axiosJWT,isLoading])
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment