Home > Enterprise >  REACT - show loader spinner by setState inside .map()
REACT - show loader spinner by setState inside .map()

Time:11-29

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>

enter image description here

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) => {
    });
  }; 
  • Related