After looking up answers about how to download files with Axios in React I implemented the following code:
const [fileName, setFileName] = useState("")
const [extension, setExtension] = useState("")
const downloadFile = useCallback(async (path) => {
Axios.get(
`http://localhost:8080/api${path}`,
{ responseType: 'blob' })
.then(res => {
let headers = res.headers['content-disposition']
let fileName = headers.split('filename=')[1].split('.')[0]
let extension = headers.split('.')[1].split(';')[0]
setFileName(fileName)
setExtension(extension)
return res.data
})
.then(blob => {
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
const fullFileName = fileName + "." + extension
link.href = url
link.download = fullFileName;
document.body.appendChild(link)
link.click()
link.remove()
URL.revokeObjectURL(url)
})
.catch(err => console.log(err))
},
[]
)
I was looking to set the filename and extension in a useState
in the first .then()
and then use it to name the downloaded file its original name. However, I came to see that it simply doesn't executes the setters before the next .then()
call, so the fileName
and extension
variables are still empty strings by then, and it gives it a default name because of it. How could I make it pass on the correct values to the next function in the chain?
Callbacks are called with its context from when they are created. So:
downloadFile
with fileName
is emptydownloadFile
in this contextthen
you change widget state - rerenderdownloadFile
callback is created with fileName
populated BUT your old callback is runningthen
with the old context.Easy solution:
Don't store fileName
and extension
in widget state if you do not have to. Use simple variables.
const downloadFile = useCallback(async (path) => {
let fileName;
let extension;
Axios.get(
`http://localhost:8080/api${path}`,
{ responseType: 'blob' })
.then(res => {
let headers = res.headers['content-disposition']
fileName = headers.split('filename=')[1].split('.')[0]
extension = headers.split('.')[1].split(';')[0]
return res.data
})
.then(blob => {
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
const fullFileName = fileName + "." + extension
link.href = url
link.download = fullFileName;
document.body.appendChild(link)
link.click()
link.remove()
URL.revokeObjectURL(url)
})
.catch(err => console.log(err))
},
[]
)