Got an array on objects from the server. Want to display for the user a loader spinner when the request is lodaing.
const onDownland = (reportId: string) => {
setDownloadLoadingState(() => true);
backendAPIAxios.get(`/download/${reportId}`)
.then((response: AxiosResponse<IDownloadResponse>) => {
})
.catch((e: AxiosError) => {
}).finally(() => {
setDownloadLoadingState(() => false);
});
};
The problem is I get multiple objects from the server, and I got one state that changes all of the objects UI.
<Button>
{!props.downloadLoadingState ?
<MSvg
name='download'
className={classes['svgContainerBlack']}
onClick={() => props.onDownload(history.id!)}
/> :
<Tooltip title={<h1 style={{ fontSize: '17px' }}>Loading</h1>} placement="left" arrow>
<CircularProgress color="inherit" />
</Tooltip>
}
</Button>
CodePudding user response:
If you move your loadingState into the Button component, you can have independent spinners for each object.
You can set the onDownload
prop to an async function (i.e. a function returning a Promise), and manage the loading state inside the button component, instead of in its parent.
Something like this might work:
// your button component
const [downloadLoadingState, setDownloadLoadingState] = useState(false);
...
<Button>
{!downloadLoadingState ? // Now looking into local state, instead of prop
<MSvg
...
onClick={() => {
setDownloadLoadingState(true)
props.onDownload(history.id!).finally(() => setDownloadLoadingState(true))
}
}
/> :
<Tooltip ...>
...
</Tooltip>
}
</Button>
// in the parent component, keep only the fetching in onDownload and remove the loading state management
// then, return the axios promise so the .finally() can be used inside the button component
const onDownload = (reportId: string) => {
return backendAPIAxios.get(`/download/${reportId}`)
.then((response: AxiosResponse<IDownloadResponse>) => {
})
.catch((e: AxiosError) => {
});
};