Reputation: 1016
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
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