Rumah  >  Soal Jawab  >  teks badan

Tajuk yang ditulis semula ialah: Memanggil React Promise.all().then() sebelum setiap setState daripada promise.then() diberikan

<p>Saya cuba membuat 200 panggilan ke sumber jauh untuk dipaparkan dalam jadual saya, sambil memaparkan bar kemajuan untuk menunjukkan bilangan panggilan yang tinggal. </p> <p>Gunakan contoh ini untuk menunjukkan cara menggunakan <code>Fetch()</code> dan <code>Promise.all()</code> untuk memanggil <code>setState()< / kod> untuk mengemas kini data baharu. </p> <p>Masalah saya ialah dengan <kod>.then()</code> setiap janji, yang mengira beberapa logik dan kemudian memanggil <code>setState()</code> </p> <p>Bar kemajuan saya menggunakan <kod>Object.keys(data).length</code> </p> <p>Selepas <code>Promise.all()</code> mencetuskan keadaan "Lengkap", mengalih keluar bar kemajuan, janji itu sendiri masih memanggil <kod>then()</code> , yang menyebabkan bar kemajuan disembunyikan sebelum semua janji yang diselesaikan dipaparkan. </p> <p>Bagaimana untuk menangani masalah ini dengan betul? </p> <hr /> <p>Demo, gunakan <code>setTimeout()</code> </p> <p>Masalahnya ialah <code>Promise.all.then: 20</code> hendaklah selepas <code>Render 20</code>. </p> <pre class="brush:none;toolbar:false;">Render 0 ... Render 12 Promise.all.then: 20 # Saya memerlukan ini untuk dilog selepas setiap Render Render 13 ... Render 19 Render 20 </pra> <p>Untuk membuat demo menunjukkan masalah, bar kemajuan telah dialih keluar (bertukar merah) sebelum ia diisi sepenuhnya.</p> <p><br /></p> <pre class="brush:js;toolbar:false;">const { useState } = React; const Contoh = () => { const [selesai, setDone] = useState(false); const [data, setData] = useState({}); const demoData = Array.from(Array(20).keys()); const demoResolver = (x) => Janji baharu(res => setTimeout(() => res(x), Math.random() * 1250)) const loadData = () => { const promises = demoData.map(c => demoResolver(c)); promises.forEach(janji => { janji .then(r =>> { setTimeout(() => { setData(p => ({ ...p, [r]: r })); }, 500); }) }); Janji.semua(janji) .then(r =>> { console.log('Promise.all.then: ', r.length) setDone(benar); }) } console.log('Render', Object.keys(data).length); const progressBarIsShownDebugColor = (selesai) ? 'bahaya' : 'is-info'; kembali ( <section className='section'> <h1 className='title is-3'>{'Contoh'}</h1> <kemajuan max={demoData.length} value={Object.keys(data).length} className={'progress my-3 ' + progressBarIsShownDebugColor} /> <butang onClick={loadData}>Mula</button> </section> ) } ReactDOM.render(<Contoh />, document.getElementById("react"));</pre> <pre class="brush:css;toolbar:false;">.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"></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></pre> <p><br /></p>
P粉162773626P粉162773626427 hari yang lalu372

membalas semua(1)saya akan balas

  • P粉426780515

    P粉4267805152023-08-21 00:02:16

    Masalah yang ditunjukkan dalam kod di atas ialah selepas mendapat data, terdapat kelewatan async 500ms tambahan sebelum menetapkan keadaan. Dalam kod sebenar, ia kelihatan seperti terdapat pemprosesan tambahan (mungkin segerak) yang menyebabkan setData.all dipanggil selepas.

    Perkara terbaik untuk dilakukan ialah membuat done作为一个计算属性而不是一个单独的状态,因为在那个点上,您不需要依赖于状态设置竞争,并且Object.keys(data).length cukup murah supaya ia tidak merendahkan prestasi (dan anda menggunakannya di kawasan lain, jika ia menjadi masalah, anda boleh menyimpannya ke dalam pembolehubah).

    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>

    balas
    0
  • Batalbalas