Last active
June 10, 2024 15:40
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { atom } from 'recoil'; | |
// notification | |
export const commonNotification = atom({ | |
key: 'commonNotification', | |
default: { | |
isVisible: false, | |
message: '', | |
}, | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 }; |
@praveencastelino I'll check it in a few and let you know if I can reproduce and what is the fix!
Thanks @ulises-jeremias
Ulises, tienes un ejemplo de como integrar todo este en una App? 🤔
@nappalm ahora mismo no tengo uno pero voy a ver de crear uno dentro de poco!
Thanks again for sharing
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@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 👌🏻