Estoy tratando de usar el botón de carga de MUI y cambiar el estado de carga del botón cuando se hace clic en él. El problema es que siempre obtengo falso para downloadLoading , incluso si configuro su estado en true en el evento onClick .
Tengo la función asíncrona ( downloadFile ) en onClick , pero estoy configurando el estado de carga antes de la función. Cuando registro el estado de downloadLoading dentro de la función onClick y async, es false . Cuando elimino la función downloadFile de onClick , el estado se establece en true y puedo ver el indicador de carga. ¿Como puedó resolver esté problema? ¿Por qué está pasando?
export const Row: React.FC<IProps> = ({ record, }: IProps): JSX.Element => { const [downloadLoading, setDownloadLoading] = useState<boolean>(false); useEffect(() => { return () => { setDownloadLoading(false); }; }, []); const download = (content: any, fileName: string) => { const link = document.createElement("a"); link.setAttribute("href", URL.createObjectURL(content)); link.setAttribute("download", `${fileName}.pdf`); link.style.visibility = "hidden"; document.body.appendChild(link); link.click(); document.body.removeChild(link); }; const downloadFile = async ( e: React.MouseEvent<HTMLElement>, id: string | undefined, fileName: string ) => { e.preventDefault(); try { const response = await fetch( `http://localhost:8080/download/id/` + id ); if (!response.ok) { response.json().then((value) => { console.log("val",value) }); } else { const content = await response.blob(); download(content, fileName); } setDownloadLoading(false); } catch (e) { console.log("error",e) } }; return ( <> <TableRow> <TableCell align="left" size="medium"> {record.name} </TableCell> <TableCell size="small"> <OutlinedCustomButton loading={downloadLoading} loadingIndicator={<CircularProgress color="inherit" size={20} />} loadingPosition="end" endIcon={<FileDownloadIcon />} fullWidth onClick={(e) => { setDownloadLoading(true); console.log(downloadLoading); downloadFile(e, record.id, record.name); }} > Download </OutlinedCustomButton> </TableCell> </TableRow> </> ); };Obtiene false para downloadLoading probablemente debido a esta parte. En cada renderización, está configurando var en falso:
useEffect(() => { return () => { setDownloadLoading(false); }; }, []);Si ya está inicializando la var como falsa, no necesita ese useEffect:
const [downloadLoading, setDownloadLoading] = useState<boolean>(false);Además, vale la pena mencionar aquí una buena práctica: si su var contiene el valor de un estado como "el proceso se está cargando" o "el proceso no se está cargando", un nombre más intuitivo sería "se está cargando", en lugar de "descargar cargando". De esa manera, puede ver de inmediato que esta var tiene un valor booleano.
Su 1st useEffect no es necesario ya que solo contiene una función de limpieza (equivalente a componentWillUnmount ) que restablece el estado al final.
Intente convertir el componente en uno basado en clases:
En la devolución de llamada onClick :
onClick={(e)=> { this.setState({downloadLoading: true}, ()=> { // download happens after downloadLoading is set to true downloadFile(e, record.id, record.name); }) }} Para probar, descargue un archivo realmente grande o aloje el servidor, ya que localhost sería bastante rápido para notar la carga.