찾다

 >  Q&A  >  본문

다시 작성된 제목은 다음과 같습니다. promise.then()의 각 setState가 렌더링되기 전에 React Promise.all().then() 호출

<p>남은 호출 수를 표시하기 위해 진행률 표시줄을 표시하는 동시에 테이블에 표시하기 위해 원격 리소스에 200번의 호출을 시도하고 있습니다. </p> <p>이 예제를 사용하여 <code>Fetch()</code> 및 <code>Promise.all()</code> / code>를 사용하여 새 데이터를 업데이트합니다. </p> <p>내 문제는 각 약속의 <code>.then()</code>에 있습니다. 이 코드는 일부 논리를 계산한 다음 <code>setState()</code>를 호출하여 데이터를 업데이트합니다. </p> <p>내 진행률 표시줄은 <code>Object.keys(data).length</code>를 사용하여 진행 상황을 표시합니다. </p> <p><code>Promise.all()</code>가 "완료" 상태를 트리거하고 진행률 표시줄을 제거한 후에도 Promise 자체는 여전히 <code>then()</code> , 해결된 모든 Promise가 표시되기 전에 진행률 표시줄이 숨겨집니다. </p> <p>이 문제를 올바르게 처리하는 방법은 무엇입니까? </p> <시간 /> <p>데모, <code>setTimeout()</code>을 사용하여 비용이 많이 드는 로직을 시뮬레이션하세요. </p> <p>문제는 <code>Promise.all.then: 20</code>이 <code>Render 20</code> 뒤에 와야 한다는 것입니다. </p> <pre class="brush:none;toolbar:false;">렌더 0 ... 렌더 12 Promise.all.then: 20 # 매 렌더 후에 이것을 기록해야 합니다. 렌더 13 ... 렌더 19 렌더 20 </pre> <p>데모에서 문제를 보여주기 위해 진행률 표시줄이 완전히 채워지기 전에 제거되었습니다(빨간색으로 바뀌었습니다).</p> <p><br /></p> <pre class="brush:js;toolbar:false;">const { useState } = 반응; const 예 = () => { const [완료, setDone] = useState(false); const [data, setData] = useState({}); const decoData = Array.from(Array(20).keys()); const 데모Resolver = (x) => new Promise(res => setTimeout(() => res(x), Math.random() * 1250)) const loadData = () => { const promise = decoData.map(c => decoResolver(c)); promise.forEach(약속 => { 약속하다 .then(r => { setTimeout(() => { setData(p => ({ ...p, [r]: r })); }, 500); }) }); Promise.all(약속) .then(r => { console.log('Promise.all.then: ', r.length) 설정완료(true); }) } console.log('렌더링', Object.keys(data).length); const ProgressBarIsShownDebugColor = (완료) ? '위험하다' : '정보입니다'; 반품 ( <section className='섹션'> <h1 className='제목은-3'>{'예'}</h1> <진행상황 최대={demoData.length} 값={Object.keys(data).length} className={'progress my-3 ' + ProgressBarIsShownDebugColor} /> <button onClick={loadData}>시작</button> </섹션> ) } ReactDOM.render(<예제 />, document.getElementById("react"));</pre> <pre class="brush:css;toolbar:false;">.as-console-wrapper { 최대 높이: 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粉162773626495일 전427

모든 응답(1)나는 대답할 것이다

  • P粉426780515

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

    위 코드에 표시된 문제는 데이터를 가져온 후 상태를 설정하기 전에 추가로 500ms의 비동기 지연이 있다는 것입니다. 실제 코드에서는 이후에 setData.all가 호출되도록 하는 추가 처리(아마도 동기식)가 있는 것처럼 들립니다.

    가장 좋은 방법은 성능이 저하되지 않을 정도로 done作为一个计算属性而不是一个单独的状态,因为在那个点上,您不需要依赖于状态设置竞争,并且Object.keys(data).length 저렴하게 만드는 것입니다(그리고 다른 영역에서 사용하다가 문제가 발생하면 변수에 캐시할 수 있습니다).

    으아악

    으아악 으아악 으아악

    회신하다
    0
  • 취소회신하다