How to use data stored in cache with SWR hooks, and how to make SWR fetch only one time

9k views Asked by At

I have a component that fetch data on mount thanks to a useEffect hooks. I'd like it to not refetch data on mount, and instead use the 'cached' data provided by useSwr hooks when i re-navigate to this component. Im not sure how to do this. What i have read is that you can call swr like this :

const { data } = useSwr('same route as previous one')

and it 'll gives you the data stored in cache by the previous swr call.


const CategoryList = ({setLoading}) => {

    const [category, setCategory] = useState('');
    const [mounted, setMounted] = useState(false);
    const [parameters, setParameters] = useState({});
    const company_id = localStorage.getItem('company_id')

    const session = new SessionService();
    const { dataFromFetch, error } = useSWR([mounted ? `${session.domain}/company/${company_id}/category-stats` : null, parameters ], url =>
      session.fetch(url, {
          method: 'GET',
      })
      , {
          onSuccess: (dataFromFetch) => {
            setCategory(dataFromFetch)
            setLoading(false)
            setMounted(false)
          },
          onError: (err, key, config) => {
            console.log("error", err)
          }
      }
  )

  useEffect(() => {
    setMounted(true)
    setLoading(true)
  }, [])

    return (
        <div className={classes.CategoryList}>
            <h5>Parc de véhicules</h5>
            <div className={classes.CategoriesCards}>
            {category.data? category.data.map((element, index) => {
                return <CategoryItem
                            category={element.data.name}
                            carNumber={element.stats.nb_vehicles}
                            locating={element.stats.nb_booked}
                            available={element.stats.nb_available}
                            blocked={element.stats.nb_unavailable}
                            percentage={(element.stats.nb_booked / element.stats.nb_vehicles * 100).toFixed(2)}
                            key={index}
                        />
            }): null}
            </div>
        </div>
    )
}

export default CategoryList;

Plus, in an other hand, i'd like my SWR hooks not to consistently try to refetch data like it is dooing actually. What i tried is passing options after my fetcher function, like it is stipulate in this post SWR options explanation. Actually my component is trying to refetch data every 5-10seconds, though unsuccesfully thanks to my 'mounted' condition which result in a 'null' route ( which is the recommended way to do it according to the documentation ). It still sends a request with response 404, which i'd like to avoid.

const [parameters, setParameters] = useState({
      revalidateOnFocus: false,
      revalidateOnMount:false,
      revalidateOnReconnect: false,
      refreshWhenOffline: false,
      refreshWhenHidden: false,
      refreshInterval: 0
    });
    const company_id = localStorage.getItem('company_id')

    const session = new SessionService();
    const { dataFromFetch, error } = useSWR([mounted ? `${session.domain}/company/${company_id}/category-stats` : null, parameters ], url =>
      session.fetch(url, {
          method: 'GET',
      })
      , {
          onSuccess: (dataFromFetch) => {
            setCategory(dataFromFetch)
            setLoading(false)
            setMounted(false)
          },
          onError: (err, key, config) => {
            console.log("error", err)
          }
      }
  )
1

There are 1 answers

2
Ro Milton On

According to SWR's documentation, the hook's API is

const { data, error, isValidating, mutate } = useSWR(key, fetcher, options)

In your code, you're passing the options as part of an array in the first argument, when it should be the third.

A minor refactor shows how it can be fixed:

const parameters = {
  revalidateOnFocus: false,
  revalidateOnMount: false,
  revalidateOnReconnect: false,
  refreshWhenOffline: false,
  refreshWhenHidden: false,
  refreshInterval: 0,
};

const company_id = localStorage.getItem( "company_id" );

const session = new SessionService();

const fetcher = (url) =>
  session.fetch(url, {
    method: "GET",
  });

const key = mounted
  ? `${session.domain}/company/${company_id}/category-stats`
  : null;

const { data, error } = useSWR(key, fetcher, parameters );

You've also over-complicated your code quite a bit - there's no need for onSuccess or onError handlers - you can simply use the returned values data and error instead.

Also, no need to save the fetched data to state by using setCategory. Just read directly from data. That's the benefit of of SWR It will auto-magically trigger re-renders when data is fetched.