LeCoda
LeCoda

Reputation: 1016

How to make SWR only fetch data when user changes date values?

I'm trying to use SWR, and while it's awesome, it keeps fetching data over and over.

I want it to only fetch data again when there has been change to the time interval.

I have been trying to use mutate to achieve this, but it looks like it's not the right approach. Referencing this post Too many re-renders when setting state - useSWR

import useSWR from 'swr';
import { useState } from 'react';

import { apiRequest } from '../../../util/util';
import { format } from 'date-fns';
import groupBy from 'lodash/groupBy';

const fetchSentiment = async (url) => {
  let sentiments = await apiRequest(url);
  sentiments = sentiments.map((el) => ({
    ...el,
    createdDay: format(new Date(el.created * 1000), 'yyyy-MM-dd'),
  }));
  sentiments = groupBy(sentiments, 'createdDay');
  return sentiments;
};

export default function useAnalytics() {
  let d = new Date();
  d.setMonth(d.getMonth() - 1);

  const [dateRange, setDateRange] = useState([d.getTime(), Date.now()]);
  const [startDate, endDate] = dateRange;
  const [shouldFetch, setShouldFetch] = useState(true);

  const handleChange = (e) => {
    //Clean up this code
    if (e[0] != null && e[1] != null) {
      e[0] = e[0].getTime();
      e[1] = e[1].getTime();
    }
    setDateRange(e);
    setShouldFetch(true);
  };

  const { data: sentimentData, error: sentimentError } = useSWR(
    shouldFetch
      ? `xxx=${startDate}&endTime=${endDate}`
      : null,
    fetchSentiment
  );

  const { data: expressionsData, error: expressionsError } = useSWR(
    shouldFetch
      ? `xxx=${startDate}&endTime=${endDate}`
      : null,
    apiRequest
  );

  if (psychometricError || sentimentError || expressionsError) {
    console.log(psychometricError);
  }

  return {
    sentimentData,
    expressionsData,
    overall,
    handleChange,
    setDateRange,
    // sentimentStatistical,
    startDate,
    endDate,
  };
}

How can I reduce the total amount of queries, but still have it update when a new time frame is chosen?

I was thinking of using a useEffect to monitor the change in dateRange and then make shouldFetch true?

Upvotes: 5

Views: 6928

Answers (1)

juliomalves
juliomalves

Reputation: 50348

If I understood correctly, you only want to fetch new data in both useSWR calls when the dateRange values change.

You can start by replacing useSWR with useSWRImmutable to disable the automatic revalidation done by SWR. You can then use an array as the key parameter in the useSWRImmutable calls to include startDate and endDate. This forces the fetcher function to re-run every time one of these variables is modified.

Here's a small refactor of your original code that implements the above suggestions, and also removes the need for the extra shouldFetch state variable.

import useSWRImmutable from 'swr/immutable';

export default function useAnalytics() {
    const [dateRange, setDateRange] = useState(() => {
        const d = new Date();
        d.setMonth(d.getMonth() - 1);
        return [d.getTime(), Date.now()];
    });
    const [startDate, endDate] = dateRange;

    const handleChange = (e) => {
        if (e[0] != null && e[1] != null) {
            e[0] = e[0].getTime();
            e[1] = e[1].getTime();
        }
        setDateRange(e);
    };

    const { data: sentimentData, error: sentimentError } = useSWRImmutable(
        // Pass an array that includes `startDate` and `endDate`
        [`xxx=${startDate}&endTime=${endDate}`, startDate, endDate],
        fetchSentiment
    );

    const { data: expressionsData, error: expressionsError } = useSWRImmutable(
        // Pass an array that includes `startDate` and `endDate`
        [`xxx=${startDate}&endTime=${endDate}`, startDate, endDate],
        apiRequest
    );

    if (psychometricError || sentimentError || expressionsError) {
        console.log(psychometricError);
    }

    return {
        sentimentData,
        expressionsData,
        overall,
        handleChange,
        setDateRange,
        startDate,
        endDate
    };
}

Upvotes: 5

Related Questions