P粉4267805152023-08-21 00:02:16
The problem shown in the code above is that after getting the data, there is an additional 500ms async delay before setting the state. In the actual code, it sounds like there is additional processing (probably synchronous) that causes setData
to be called after .all
.
The best practice is to have done
as a computed property rather than a separate state, because at that point you don't need to rely on the state to set up contention, and Object.keys( data).length
is cheap enough that it doesn't hurt performance (and you use it in other areas, you can cache it into a variable if it becomes a problem).
const [data, setData] = useState({}); const done = Object.keys(data).length === 20; // 在实际代码中为200
const { useState } = React; const Example = () => { const [data, setData] = useState({}); const done = Object.keys(data).length === 20; // 在实际代码中为200 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); }) }); } 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>