I'm trying to call 200 remote resources to show in my table, with a progress bar showing the amount of calls remaining.
Using this example on how to use Fetch()
with Promise.all()
to call setState()
with the new data.
My problem lies in the .then()
for each promise, which computes some logic, and then calls setState()
to update the data.
My progress bar uses Object.keys(data).length
to show the progress.
After the Promise.all()
triggers the 'done' state, removing the progess bar, the promises themself are still calling there then()
which causes the progress bar to be hidden before it shows the full amount of promises resolved.
What is the correct way of dealing with this?
Demo, which uses setTimeout()
to mimic the expensive logic.
Issue is that the Promise.all.then: 20
should become after Render 20
.
Render 0
...
Render 12
Promise.all.then: 20 # I need this to log after each Render
Render 13
...
Render 19
Render 20
To make the demo show the issue the progress bar is removed (turned red) before it's completely full.
const { useState } = React;
const Example = () => {
const [done, setDone] = useState(false);
const [data, setData] = useState({});
const demoData = Array.from(Array(20).keys());
const demoResolver = (x) => new Promise(res => setTimeout(() => res(x), Math.random() * 1250))
const loadData = () => {
const promises = demoData.map(c => demoResolver(c));
promises.forEach(promise => {
promise
.then(r => {
setTimeout(() => {
setData(p => ({ ...p, [r]: r }));
}, 500);
})
});
Promise.all(promises)
.then(r => {
console.log('Promise.all.then: ', r.length)
setDone(true);
})
}
console.log('Render', Object.keys(data).length);
const progressBarIsShownDebugColor = (done)
? 'is-danger'
: 'is-info';
return (
<section className='section'>
<h1 className='title is-3'>{'Example'}</h1>
<progress
max={demoData.length}
value={Object.keys(data).length}
className={'progress my-3 ' + progressBarIsShownDebugColor}
/>
<button onClick={loadData}>Start</button>
</section>
)
}
ReactDOM.render(<Example />, document.getElementById("react"));
.as-console-wrapper { max-height: 50px !important; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
<div id="react"></div>