Skip to content

Instantly share code, notes, and snippets.

@ulises-jeremias
Last active June 10, 2024 15:40
Show Gist options
  • Select an option

  • Save ulises-jeremias/a27b85e3eea083278188f24de955989b to your computer and use it in GitHub Desktop.

Select an option

Save ulises-jeremias/a27b85e3eea083278188f24de955989b to your computer and use it in GitHub Desktop.
Examples of hooks utils using axios, recoil.js, keycloak-js, @react-keycloak/web and more.
import { useCallback, useEffect, useState } from 'react';
import { useSetRecoilState } from 'recoil';
import { useKeycloak } from '@react-keycloak/web';
import { commonNotification } from './common';
/**
* Returns the auth info and some auth strategies.
*
*/
export const useAuth = () => {
const [keycloak, initialized] = useKeycloak();
const setNotification = useSetRecoilState(commonNotification);
const [user, setUser] = useState({});
// fetch user profile
useEffect(() => {
if (!initialized) {
return;
}
const fetchUserInfo = async () => {
try {
const userProfile = await keycloak.loadUserProfile();
setUser({ ...userProfile, fullName: `${userProfile.firstName} ${userProfile.lastName}` });
} catch (err) {
setNotification({ isVisible: true, message: err.message });
}
};
if (keycloak.authenticated) {
fetchUserInfo();
}
}, [keycloak, initialized]);
return {
isAuthenticated: !!keycloak.authenticated,
initialized,
meta: {
keycloak,
},
token: keycloak.token,
user,
roles: keycloak.realmAccess,
login: useCallback(() => { keycloak.login(); }, [keycloak]),
logout: useCallback(() => { keycloak.logout(); }, [keycloak]),
register: useCallback(() => { keycloak.register(); }, [keycloak]),
};
};
export default {
useAuth,
};
import axios from 'axios';
import { useState, useEffect } from 'react';
import { useAuth } from 'auth-hook';
/**
* Returns an authorizated axios instance
*
* @param {Object} config is the default config to be sent to the axios creator
*
* @return {Object} an object containing the axios instance and the initialized prop
*
*/
export const useAxios = (config = {}) => {
const { token, initialized: authInitialized } = useAuth();
const [initialized, setInitialized] = useState(false);
const [axiosInstance, setAxiosInstance] = useState({});
useEffect(() => {
const instance = axios.create({
...config,
headers: {
...(config.headers || {}),
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
Authorization: authInitialized ? `Bearer ${token}` : undefined,
},
});
setAxiosInstance({ instance });
setInitialized(true);
return () => {
setAxiosInstance({});
setInitialized(false);
};
}, [token, authInitialized]);
return { axios: axiosInstance.instance, initialized };
};
export default { useAxios };
import { atom } from 'recoil';
// notification
export const commonNotification = atom({
key: 'commonNotification',
default: {
isVisible: false,
message: '',
},
});
import { useCallback } from 'react';
// Hook defined thinking in the future. Actually it does not behave as a hook.
export const useErrorHandler = (hookOptions = {}) => {
/**
* Error handler
*
* En la funciΓ³n se define el flujo de la aplicaciΓ³n en caso de un error.
*
* @param {String | Object | Error} error
* @returns {String[2]}
*
*/
const handleError = useCallback((error, options) => (
// use error and options here
['message', '']
), []);
return {
handleError,
};
};
export default { useErrorHandler };
import { useState, useCallback } from 'react';
import { useHistory } from 'react-router-dom';
import { useSetRecoilState } from 'recoil';
import { commonNotification } from './common';
import { useAxios } from './axios-hook';
import { useErrorHandler } from './error-hook';
const API_BASE_URL = '/api/';
const REQUEST_TIMEOUT = 5;
/**
*
* @param {Object} options request options
* @param {String} options.url The request url
* @param {String} options.method The request http method
* @param {Object} requestParams.initialValue The response data initial value
*
* @see useAxios
* @see axiosDefaultConfig
* @see mapResponseToData
*
* @return {Object} return an object containing the data, isLoading and the request strategy.
*
*/
export const useRequest = (options = {}, axiosConfig = {}) => {
const [data, setData] = useState(options.initialValue);
const [isLoading, setLoading] = useState(false);
const setNotification = useSetRecoilState(commonNotification);
const { handleError } = useErrorHandler();
const { axios, initialized: axiosInitialized } = useAxios({
...axiosDefaultConfig,
...axiosConfig,
});
const history = useHistory();
/**
* Specific request for options
*
* @param {Object} requestParams Request
* @param {Object} requestParams.params The request query params
* @param {Object} requestParams.data The request body data
*
*/
const request = (requestParams) => {
if (!axiosInitialized) {
return;
}
const fetchData = async () => {
setLoading(true);
try {
const response = await axios({ ...options, ...requestParams });
const responseData = mapResponseToData(response);
setData(responseData);
setLoading(false);
} catch (err) {
const [message, redirect] = handleError(err);
setLoading(false);
setNotification({ message, isVisible: true });
if (redirect) {
history.push(redirect);
}
}
};
fetchData();
};
const fetch = useCallback(request, [axiosInitialized]);
return { isLoading, data, fetch };
};
/**
* Request default config for axios creator
*
* @see API_BASE_URL
* @see REQUEST_TIMEOUT
*/
const axiosDefaultConfig = {
baseURL: API_BASE_URL,
withCredentials: true,
timeout: REQUEST_TIMEOUT,
};
/**
* Maps axios response to data
*
* @param {Object} response
*
* @return {Object} the response data
* @throws {Object} throws an object containing the axios response
*/
export const mapResponseToData = (response) => {
const { data } = response;
return data;
};
export default { useRequest };
@jayrp11
Copy link
Copy Markdown

jayrp11 commented Apr 26, 2021

Thanks for the neat code. It will be helpful if you add example of how to use useRequest hook in functional component.

@emrivero
Copy link
Copy Markdown

emrivero commented Dec 9, 2021

Great snippets! Thanks πŸ‘

@praveencastelino
Copy link
Copy Markdown

praveencastelino commented Mar 28, 2022

@ulises-jeremias
I did a quick implementation but noticed that the first time, the request doesn't work as Axios initialisation would be pending. I need to make an additional call to make it work. Am I doing something wrong?

`
const { isLoading, data, fetch } = useRequest()

useEffect(() => {
let options = { url: '/applicant', method: 'GET', initialValue: [] }
fetch(options);
}, []);

`

@ulises-jeremias
Copy link
Copy Markdown
Author

ulises-jeremias commented Mar 28, 2022

@jayrp11 you can find a real usage example of the other hooks here! https://gist.github.com/ulises-jeremias/2360fefd8ded8d5a8f87c3258a2b5a0d
I'll add here some examples of the useRequest later πŸ‘ŒπŸ»

@ulises-jeremias
Copy link
Copy Markdown
Author

@praveencastelino I'll check it in a few and let you know if I can reproduce and what is the fix!

@jayrp11
Copy link
Copy Markdown

jayrp11 commented Mar 28, 2022

@nappalm
Copy link
Copy Markdown

nappalm commented Nov 22, 2022

Ulises, tienes un ejemplo de como integrar todo este en una App? πŸ€”

@ulises-jeremias
Copy link
Copy Markdown
Author

@nappalm ahora mismo no tengo uno pero voy a ver de crear uno dentro de poco!

@abdoukhadre-searching
Copy link
Copy Markdown

Thanks again for sharing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment