Reputation: 156
I am using useQuery
and its refetch
option to download a file in the frontend. The download process is of two steps, and I am displaying the below notifications to the users:
Both these notifications are displayed to the user, and the idea is to allow the user to navigate anywhere in the application while the download is being processed.
There are two APIs:
API 1 - used for displaying the first notification. I use refetch
option with this to check if the download is ready.
API 2 - used for downloading the file once the API returns "Ready for download" status
For this, I have created a custom hook
where I call the useQuery
for each API
Custom hook structure:
export const useFileDownload = () => {
const [fileReady, setFileReady] = useState(false);
const { isError, isLoading, mutate } = useDownloadBegin({ //this uses useQuery with refetch option
onSuccess: (data) => {
setFileReady(true);
}
});
const { isError, isLoading, mutate } = useDownloadFile({ //this downloads file using useQuery
enabled: fileReady;
. . .
});
}
My Component:
<DownloadModal {props} />
Download Modal:
export const DownloadModal = ({...props}) => {
const { isDownloading } = useFileDownload();
return(
<>Download Modal</>
)
}
What is the issue?
Once I navigate to another page, API 1 stops getting executed, and I am never able to download the file using API 2. It works absolutely fine if I stay on the same page.
I believe, the hook does not get executed once I go to another page, as the component gets unmounted.
How do I make sure that hook gets executed asynchronously even when navigated away from the component?
What have I tried?
I explored different options available in tanstack useQuery like refetchIntervalInBackground
.
Also, since I do not have a store
in my application, I am trying to work around context
to see if I can use it for my purpose. But, I am still not sure about it.
Upvotes: 3
Views: 943
Reputation: 306
You're on the right track. You need a Context Provider at the top of your app, such that every page the user might visit following the download process initiating will be within the provider's context, e.g.
<DownloadProvider>
<Page1 />
<Page2>
<Page2a />
<Page2b />
</Page2>
<Page3 />
</DownloadProvider>
You can make use of your existing useFileDownload
hook in the provider. You don't say what initiates the download process, so I'm guessing it's a button click or similar, in which case your useFileDownload
hook will need to return the ability for the hook to know it can begin the process, e.g. (using an enableDownload
state property as demonstrated here):
Custom hook
export const useFileDownload = () => {
const [enableDownload, setEnableDownload] = useState(false);
const [fileReady, setFileReady] = useState(false);
const {
isError,
isLoading,
mutate
} = useDownloadBegin({ //this uses useQuery with refetch option
enabled: enableDownload,
onSuccess: (data) => {
setFileReady(true);
}
});
const {
isError,
isLoading,
mutate
} = useDownloadFile({ //this downloads file using useQuery
enabled: fileReady;
...
});
return {
setEnableDownload
};
}
The idea being that whatever UI initiates the download process can just call setEnableDownload(true)
.
Your context provider will make use of this hook, this will make setEnableDownload
available to any descendant component that needs to use it:
download-provider.jsx
const DownloadContext = createContext({});
const DownloadProvider = ({ children}) => {
const { setEnableDownload } = useFileDownload();
const contextValues = { setEnableDownload };
return (
<DownloadContext.Provider value={contextValues}>
{children}
</DownloadContext.Provider>
);
};
export default DownloadProvider;
export { DownloadContext };
You can then add your context provider to the top of your page hierarchy:
import DownloadProvider from './download-provider.jsx';
...
return (
<DownloadProvider>
<...Top level page component...>
</DownloadProvider>
);
...
And, finally, in the component that needs to initiate the download, you can use the provided setEnableDownload
method:
import { DownloadContext } from '../../download-provider.jsx';
...
const { setEnableDownload } = useContext(DownloadContext);
...
and call it as appropriate to initiate the download process, and because the hook is being used by a provider at the top of your component tree, it will continue operating regardless of the user navigating around the app.
Upvotes: 1