arthurfiorette / axios-cache-interceptor

📬 Small and efficient cache interceptor for axios. Etag, Cache-Control, TTL, HTTP headers and more!
https://axios-cache-interceptor.js.org
MIT License
685 stars 56 forks source link

Better document react usage. #520

Closed SpicyJungle closed 1 year ago

SpicyJungle commented 1 year ago

Hello - I tried doing what is shown in the react example, however I still get the error "setupCache() should be called only once".

axios-context.js

/* eslint-disable */

/*
 * Replace ../../src with axios-cache-interceptor
 */

import Axios from 'axios';
import { createContext, FC, useContext, useState } from 'react';
import { setupCache } from 'axios-cache-interceptor'; // axios-cache-interceptor

/** @type {import('react').Context<import('axios-cache-interceptor').AxiosCacheInstance>} */

const AxiosContext = createContext(null);
export const useAxios = () => useContext(AxiosContext);

export const AxiosProvider = ({ children }) => {

  const [axios] = useState(
    setupCache(
      Axios.create(),
      {}
    )
  );

  return <AxiosContext.Provider value={axios}>{children}</AxiosContext.Provider>;
};

_app.tsx

export default function App({
  Component,
  pageProps: { session, ...pageProps },
}: AppProps<{ session: Session }>) {
  return (
    <SessionProvider session={session}>
      <AxiosProvider>
        <Component {...pageProps} />
      </AxiosProvider>
    </SessionProvider>
  );
}

dashboard.tsx (Where I want to make the requests)

  const axios = useAxios();

  const [{ data, error, loading }, setResponse] = useState({
    data: [],
    loading: true,
    error: null
  });

  useEffect(() => {

    axios.get('https://discord.com/api/users/@me/guilds', {
      headers: {
        Authorization: `Bearer  ---`,
      },
    }).then(
      ({ data }) => setResponse({ data, loading: false, error: null }),
      (error) => setResponse({ data: [], loading: false, error })
    );

  }, []);

Thanks in advance :)

richardgarnier commented 1 year ago

This is because this part is executed everytime your context re-renders (the session changes?)

 const [axios] = useState(
    setupCache(
      Axios.create(),
      {}
    )
  );

You can probably fix it by making sure setupCache is called only once, like this for instance:

const axios = useMemo(() => {
  return setupCache(Axios.create(), {});
}, []);
SpicyJungle commented 1 year ago

I tried this, but the same issue persists.

export const AxiosProvider = ({ children }) => {

  const axios = useMemo(() => {
    return setupCache(Axios.create(), {});
  }, []);

  return <AxiosContext.Provider value={axios}>{children}</AxiosContext.Provider>;
};
arthurfiorette commented 1 year ago

The problem is that, even if you use the first time created, next renders of your component will call the setupCache() again, even if it don't use it.

SpicyJungle commented 1 year ago

Yeah. Do you have an idea on how to get around this?

arthurfiorette commented 1 year ago

Use it as a singleton

arthurfiorette commented 1 year ago

I'm sorry that the react guide is outdated, i need to updated it asap (using togheter axios-cache-hooks).

Try using axios-cache-hooks it may solve all your problems at once.

It may also be a little bit undocumented, but I'd love to help you with any problem and also use it as a documentation guide to follow when building it up.

SpicyJungle commented 1 year ago

Okay, I'll give axios-cache-hooks a shot and then get back once I've tried a bit.

SpicyJungle commented 1 year ago

I set it up, but I do still get the same error.

arthurfiorette commented 1 year ago

Have you set it up the way it says in the readme?

SpicyJungle commented 1 year ago

Yes, I followed the readme. I suppose its worth mentioning that I'm guessing createAxiosHooks was renamed to createAxiosCacheHooks and the docs just arent updated?

arthurfiorette commented 1 year ago

Yes, haha.

Create it outside of the component function.

SpicyJungle commented 1 year ago

Not sure what you mean by create it outside the component function.

getGuilds.ts

import Axios, { AxiosRequestConfig } from "axios";
import { setupCache } from "axios-cache-interceptor";
import { createAxiosCacheHooks } from "axios-cache-hooks";

export const axios = setupCache(Axios);
export const { useQuery, useMutation } = createAxiosCacheHooks();

export function getGuilds(token: string): Promise<any> {

  const guilds = axios.get("https://discord.com/api/users/@me/guilds", {
    headers: {
      Authorization: `Bearer ---`,
    },
  });

  return guilds;
}

dashboard.tsx

import { useQuery, getGuilds } from '../queries/getGuilds';

export default function DashboardPage() {
  const { data: session } = useSession();
  const [guilds, { loading, error }] = useQuery(getGuilds, "");

This is how I've currently got it set up.

arthurfiorette commented 1 year ago

I'll keep this issue open to point out lacking of documentation.

arthurfiorette commented 1 year ago

d72b122