const { useState } = React; const 範例 = () => { const [完成,setDone] = useState(false); const [數據,setData] = useState({}); const demoData = Array.from(Array(20).keys()); const demoResolver = (x) =>;新的 Promise(res => setTimeout(() => res(x), Math.random() * 1250)) const loadData = () =>; { const Promise = demoData.map(c => demoResolver(c)); Promise.forEach(promise => { 承諾 .then(r => { setTimeout(() => { setData(p => ({ ...p, [r]: r })); }, 500); }) }); Promise.all(承諾) .then(r => { console.log('Promise.all.then: ', r.length) 設定完成(真); }) } console.log('渲染', Object.keys(data).length); const ProgressBarIsShownDebugColor =(完成) ? '是危險' : '是信息'; 返回 ( <節類別名稱='節'>;{'範例'}
; <進展 最大值={demoData.length} value={Object.keys(data).length} className={'progress my-3'progressBarIsShownDebugColor} >> </節> ) } ReactDOM.render(<範例/>, document.getElementById("react"));
.as-console-wrapper { max-height: 50px !important; }</pre> <pre class="brush:html;toolbar:false;"><script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min .js"></腳本> <腳本 src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script> <連結 rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css"> <div id="react"></div></pre> <p><br />></p>
P粉4267805152023-08-21 00:02:16
上面程式碼中顯示的問題是,在取得資料後,在設定狀態之前有額外的500ms非同步延遲。在實際程式碼中,聽起來有額外的處理(可能是同步的)導致setData
在.all
之後被呼叫。
最好的做法是將done
作為一個計算屬性而不是一個單獨的狀態,因為在那個點上,您不需要依賴狀態設定競爭,並且Object.keys( data).length
足夠便宜,不會降低效能(而且您在其他區域使用它,如果它成為一個問題,您可以將其緩存到一個變數中)。
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>