想象一下,我得到了一个诺言数组(总共12个诺言),我想呈现已在页面上解析的诺言进度:1 / 12、2 / 12、3 / 12之类的东西。因此,我从这里的答案中得到了解决方法:link
我成功地计算了progressNum或百分比,并且能够console.log它们。
问题是当我尝试使用setState设置progressNum时,当所有承诺都解决时,它仅显示12/12。或先渲染一些随机数字,例如4/12,然后再渲染12/12,但我想渲染诸如从1 / 12、2 / 12、3 / 13 ... 12/12开始的数字。
Im able to console.log the progress correctly
我知道setState是异步的,所以我尝试使用react ref来操纵元素。但是也没有运气。
到目前为止,我的代码:
class App extends Component {
state = {
progress: 0,
};
handleResize = async () => {
...
// imgFiles is an array 12 File object
this.allProgress(imgFiles.map(this.resizeImg));
...
};
allProgress(promArray) {
let progress = 0;
promArray.forEach((p) => {
p.then(()=> {
progress += 1;
console.log(`${progress}/12`);
this.setState({ progress });
});
});
return Promise.all(promArray);
}
// I use Jimp package to resize the img, and then return promise
resizeImg = imgFile => new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => {
Jimp.read(reader.result)
.then(async (jimpImg) => {
const normalImg = await this.resizeMain(jimpImg, true,
imgFile.name);
const largeImg = await this.resizeMain(jimpImg, false,
imgFile.name);
resolve([normalImg, largeImg]);
})
.catch(reject);
};
reader.readAsArrayBuffer(imgFile);
});
render() {
return (
<div>
<p>{this.state.progress}</p>
<button onClick={this.handleResize} >Resize</button>
</div> )
}
我也尝试参考
class App extends Component {
state = {
progress: 0,
};
indicator = React.createRef();
changeProgress = (num) => {
this.indicator.current.innerText = `${num}/12`;
};
...
allProgress(promArray) {
let progress = 0;
promArray.forEach((p) => {
p.then(()=> {
progress += 1;
console.log(`${progress}/12`);
// the only logic that I changed:
this.changeProgress(progress);
});
});
return Promise.all(promArray);
}
...
render() {
return (
<div>
<p ref={this.indicator} />
<button onClick={this.handleResize} >Resize</button>
</div> )
}
}
答案 0 :(得分:1)
要更新进度时,可以使用setState
的回调版本,以确保不尝试使用旧值进行更新。
示例
class App extends React.Component {
state = {
done: 0,
total: 12,
data: []
};
componentDidMount() {
Promise.all(
Array.from({ length: this.state.total }, () => {
return new Promise(resolve => {
setTimeout(() => {
this.setState(
prevState => ({ done: prevState.done + 1 }),
() => resolve(Math.random())
);
}, Math.random() * 3000);
});
})
).then(data => {
this.setState({ data });
});
}
render() {
const { done, total, data } = this.state;
return (
<div>
<div>
{done} / {total} done
</div>
<div>{data.join(", ")}</div>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"><div>
答案 1 :(得分:1)
问题是您使用的Promise.all
仅在所有的诺言都得到解决时才被调用。因此,您所有的then
方法将一起被调用。因此,回调中的多个setState
调用将被分批处理,这就是为什么看不到全部计数的原因。不要使用Promise.all
来解决问题,而要让诺言按照其自然顺序解决。
class App extends React.Component{
constructor(props){
super(props)
this.state = {progress: 0, total: 12}
}
allProgress(promArray) {
let progress = 0;
//dont use Promise.all
promArray.forEach((p) => {
p.then(()=> {
progress += 1;
console.log(`${progress}/12`);
this.setState({ progress });
});
});
}
componentDidMount(){
const p = []
for(let i =0;i<12;i++){
p.push(new Promise((resolve, reject)=>{setTimeout(resolve, Math.random() * 5000)}))
}
this.allProgress(p)
}
render(){
return (
<div>{this.state.progress} / {this.state.total}</div>
)
}
}
ReactDOM.render(<App />, document.getElementById("app"))
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>