重写后的标题为:在React Promise.all().then()之前调用每个来自promise.then()的setState被渲染
P粉162773626
P粉162773626 2023-08-20 11:02:53
0
1
330

我正在尝试调用200个远程资源以在我的表格中显示,同时显示一个进度条来显示剩余的调用次数。

使用这个示例来演示如何使用Fetch()Promise.all()来调用setState()来更新新数据。

我的问题在于每个promise的.then(),它计算一些逻辑,然后调用setState()来更新数据。

我的进度条使用Object.keys(data).length来显示进度。

Promise.all()触发“完成”状态后,移除进度条,promise本身仍然在调用它们的then(),这导致进度条在显示完所有已解决的promise之前就被隐藏了。

如何正确处理这个问题?


演示,使用setTimeout()来模拟昂贵的逻辑。

问题在于Promise.all.then: 20应该在Render 20之后。

Render 0 ... Render 12 Promise.all.then: 20 # 我需要这个在每个Render之后记录 Render 13 ... Render 19 Render 20 

为了使演示显示出问题,进度条在完全填满之前就被移除(变成红色)。


>

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; }
 <链接 rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css"> 


>

P粉162773626
P粉162773626

全部回复 (1)
P粉426780515

上面代码中显示的问题是,在获取数据后,在设置状态之前有额外的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 ( 

{'Example'}

) } ReactDOM.render(, document.getElementById("react"));
.as-console-wrapper { max-height: 50px !important; }
   
    最新下载
    更多>
    网站特效
    网站源码
    网站素材
    前端模板
    关于我们 免责声明 Sitemap
    PHP中文网:公益在线PHP培训,帮助PHP学习者快速成长!