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!