I've implemented a custom React hook creates a task on my API, stores the task UUID in state and then starts polling the API every 2 seconds until successful data is received.
The problem I'm facing is that I want to display the last successful data returned from the API while it's fetching or refetching for new data. Right now the query result is undefined when mutate is called. I don't want that.
The API is slow right now and it takes about 12 seconds or 6 refetches to complete the request successfully, so I want to display the old data meanwhile. I think you understand what I'm trying to say by now.
You can ignore the sendToBackground(), it's how you communicate with background service workers using Plasmo.
Tools I'm using:
- Plasmo 0.81.0
- React 18.2.0
- React Query ^3.39.3
use-suggestions.ts
export function useSuggestions(
text: string,
id: string,
): UseQueryResult<TaskTextStatus> {
const [task, setTask] = useState<string>();
const [stopRefetch, setStopRefetch] = useState(false);
const [textDebounced] = useDebounce(text, 1000);
// Triggers on input text change, calls mutate once per 1000ms
useEffect(() => {
mutate(text);
}, [textDebounced]);
// Submits text task to API, stores task UUID in `task` state
const { mutate } = useMutation(
["suggestions", id, text],
async (text: string) => {
if (!text) return;
const res = await sendToBackground<{ text: string }, TaskTextSubmit>({
name: "send-text",
body: { text },
});
return res;
},
{
onSuccess(data) {
if (!data) return;
// Sets the created task UUID
setTask(data.task_uuid);
},
onError(e) {
console.log(e, "ERROR");
},
},
);
// Activates when task_uuid is known(when task is created)
// Polls the API every 2 seconds in the background
// Stops when receives result
return useQuery(
["suggestions", id, text],
async () => {
if (!task) return;
setStopRefetch(false);
const res = await sendToBackground<{ task_uuid: string }, TaskTextStatus>(
{ name: "check-task", body: { task_uuid: task } },
);
if (res.is_success) return res;
},
{
enabled: !!task,
refetchInterval: stopRefetch ? false : 2000,
keepPreviousData: true,
refetchIntervalInBackground: true,
refetchOnWindowFocus: false,
onSuccess(data) {
if (data?.is_success) {
setStopRefetch(true);
setTask("");
}
},
onError() {
setStopRefetch(true);
},
},
);
}
With keepPreviousData addded, it returns the old data only after the first fetch. Then it sets to undefined because no data was returned from the following refetch.
Essentially, I need to keep the last data where is_success was true, up until receiving new data where is_success is also true, keeping out all the whatnot happens in the middle while refetching.
Hope I didn't make it too confusing, thanks for the help!
Some feedback:
datais not cleared just because the most recent fetch erroredkeepPreviousData: truedoes not solve your problem, it means the data will be kept during fetching when the query key changes. So in your example, ifidchanges from1to2, then data from1will be displayed to user while2is fetching. Consider if you really need it.stopRefetchfrom state. If you want really want to disable a query then setenabledtofalseYour updated
queryFncan look like this: