I've created an NPM library that shares multiple util functions. One of which is to call our endpoints. I've included Axios in my NPM library, but I'm stuck being able to set the Axios.create
instance globally.
I initially thought I could create a Provider
and set a context
, however, as my API function isn't within a hook, I cannot access the context. This is my first NPM library so unfamiliar with what is best practice.
// Provider.ts
export default function Provider({ children, config }: ProviderProps) {
window.config = config;
return (
<ContextConfig.Provider value={config}>{children}</ContextConfig.Provider>
);
}
^ Above, I tried using context API, setting a global variable, etc.
// api.ts
import Axios, { AxiosInstance, AxiosPromise, Cancel } from 'axios';
const axiosInstance = Axios.create(window.config);
const api = (axios: AxiosInstance) => ({
get: <T>(url: string, config: ApiRequestConfig = {}) =>
withLogger<T>(withAbort<T>(axios.get)(url, config)),
});
export default api(axiosInstance)
^ Above, tried to use the global variable window.config
, however, it is undefined
. Also tried converting the export to a hook to allow reading the context, however, getting errors around unsafe usage of hooks.
// index.ts
import api from './api';
import Provider from './Provider';
export { api, Provider };
The only way I can think about handling this now is using Local Storage, very much open to advise.
Cheers
CodePudding user response:
You absolutely should be able to bind your variable to the window
.
What I think has actually happened is that api.ts
has been initiated before you set window.config
, hence why it is undefined
. If you converted api.ts
default export to a function you'll be able to get the value of window.config
on each call. I.E;
// api.ts
import Axios, { AxiosInstance, AxiosPromise, Cancel } from 'axios';
const api = (axios: AxiosInstance) => ({
get: <T>(url: string, config: ApiRequestConfig = {}) =>
withLogger<T>(withAbort<T>(axios.get)(url, config)),
});
export default () => {
const axiosInstance = Axios.create(window.config);
return api(axiosInstance)
}
This may be a little less performant as you'll be calling Axios.create
on each call, however, it shouldn't be too impactful.
CodePudding user response:
Do you need the config for anything except your Axios instance?
Why not just create a Provider / Context setup that handles your api object for you?
// Create a context for the api
const ApiContext = createContext({});
// Create a Provider component.
const ApiProvider = ({ config }) => {
// recreate the api every time the provided configuration changes.
const api = useMemo(() => {
// create axios instance using the provided config.
const axiosInstance = Axios.create(config);
// create API object
return {
get: <T,>(url: string, apiConfig: ApiRequestConfig = {}) => withLogger<T>(withAbort<T>(axiosInstance.get)(url, apiConfig))
};
}, [config] /* dependency array - determines when api will be recomputed */)
return (
<ApiContext.Provider value={api}>
{children}
</ApiContext.Provider>
);
};
const useApi = () => {
// retrieve configured API from context.
const api = useContext(ApiContext);
return api;
}
// Example component to show how to retrieve api for use.
const Example = () => {
// retrieve configured API from context.
const api = useContext(ApiContext);
//OR
const api = useApi();
// use api here
return (
<div>
Content goes here
</div>
)
}
// App component to show providing config for API.
const App = () => {
// Create config (should only update reference when values need to change)
const config = useMemo(() => ({
// add config here
}), []);
return (
// pass config to API Provider.
<ApiProvider config={config}>
<Example />
</ApiProvider>
)
}