I am using the package react-native-background-downloader. my state is initialize like this :
const [downloadFile, setDownloadFile] = useState({});
after i get data from api i update my state:
setDownloadFile({
thumbnail:
'https://img.youtube.com/vi/J6rVaFzOEP8/maxresdefault.jpg',
heading: 'Guide To Becoming A Self-Taught Software Developer',
timing: 123,
status: 'Staring ...',
});
then i use the package to download the video from url
const ts = RNBackgroundDownloader.download({
id: inputUrl,
url: 'url too long to display',
destination: `${RNBackgroundDownloader.directories.documents}/test.mp4`,
});
setTask(ts);
ts.begin(async (res) => {
await setDownloadFile({
...downloadFile,
timing: res / 1024,
});
console.log('onbegin', downloadFile);
});
ts.progress(async (pr) => {
await setDownloadFile({
...downloadFile,
status: `Downloading... ${Math.round(pr * 100)}%`,
});
console.log('onProgress', downloadFile);
});
ts.done(async () => {
await setDownloadFile({
...downloadFile,
status: 'done',
});
console.log('onDone', downloadFile);
});
my problem is that the state update in .begin() in timing variable is not taking place in .progress()
initially => timing:123,
.begin() => timing: res / 1024,
.progress() => timing:123 (as it was in first place);
downloadFile
is a local const. It will never change, and that's not what setDownloadFile
tries to do. The purpose of setting state is to tell the component to rerender. On that next render, a new local variable will be created, which gets the new value.
So every time you do:
setDownloadFile({
...downloadFile
// etc
})
... you are making a copy of the downloadFile
in this closure. Ie, the one that existed at the time you called RNBackgroundDownloader.download.
The simplest fix is to use the function version of setDownloadFile. You can pass a function to a state setter, and it will be called with the most recent state, and then you can base the new state on that. For example:
ts.progress((pr) => {
setDownloadFile(previous => {
return {
...previous,
status: `Downloading... ${Math.round(pr * 100)}%`,
}
});
});
I removed the async/await, because setting state does not return a promise so it served no purpose. I removed the logging too. If you want it, you'll need to put it inside the function.