React如何在每次改变状态数组的循环迭代后更新ui



我正在处理这个react组件。我希望它使用循环修改数组,并在每次迭代后反映UI中的更改。我还添加了一些代码来停止程序,这样每次迭代都会显示很短的时间。

至于UI,我有数组中的数字,后面跟着一个按钮来启动循环。似乎在按下按钮后,ui就冻结了,数组就会显示出来,但只是在循环的最后一次迭代之后。我希望屏幕上的数组在每次循环迭代后都会发生变化。我尝试使用这个.forceUpdate((,但它没有改变任何内容。我还尝试使用spread(…(运算符来更改状态,但这也没有改变任何内容。下面粘贴了相关代码和GitHub。代码可以在项目文件的src/ChangingArray.js中找到。提前谢谢。

import React, { Component } from 'react'
export default class ChangingArray extends Component {
constructor(props) {
super(props);
this.state = {
array: [1, 2, 3]
}
this.modifyArray = this.modifyArray.bind(this);
}
modifyArray = () => {
for (let i = 0; i < 15; i++) {
let newArray = [];
for (let j = 0; j < this.state.array.length; j++) {
newArray[j] = this.state.array[j];
}
newArray[i % newArray.length] = i;
this.setState({
array: [...newArray],
})
this.forceUpdate();
//Code to halt the program
const date = Date.now();
let currentDate = null;
do {
currentDate = Date.now();
} while (currentDate - date < 250);
}
}
render() {
return (
<div>
{this.state.array}
<button onClick={this.modifyArray}>modify</button>
</div>
)
}
}

https://github.com/AntonM-248/longestPalindromicSubstringVisualizer

通过进行

do {
currentDate = Date.now();
} while (currentDate - date < 250);

你正在同步阻塞线程,所以你的UI显然会冻结:

我不确定我是否理解了你想要实现的目标,但如果你想在进入下一个循环之前阻止一段时间的循环执行,你需要实现一个异步迭代器,让我向你展示如何:

function makeAsyncArray(arr, delay) {
return {
[Symbol.asyncIterator]() {
let i = 0;
return {
next() {
const done = i === arr.length;
const value = done ? undefined : arr[i];
i++;
return new Promise((res) =>
setTimeout(() => res({ value, done }), delay)
);
},
return() {
// This will be reached if the consumer called 'break' or 'return' early in the loop.
return { done: true };
},
};
},
};
}

此函数返回一个名为异步迭代器的特殊对象,这种迭代器可以使用以下语法进行迭代:

for await (const el of arr) //do something

这个迭代器返回的每个元素都是一个Promise,所以它可以在async function内等待,如果我们想制作延迟的循环,在继续循环之前等待一些东西,这就是我们所需要的。在这个例子中,我只使用了一个带有setTimeout的延迟来异步地产生和阻止循环一段时间,但您可以使用这个逻辑来解决任何其他异步逻辑的Promise(例如获取请求的结果(。

这是这个逻辑的一个工作React实现:

const arr = makeAsyncArray([1, 2, 3, 4, 5,6,7,8,9,10], 1000);
export default function App() {
const [data, setData] = useState([]);
// Data array will be populated adding one element every 1000ms since we have initialized the async iterator to resolve after 1000ms
useEffect(() => {
(async () => {
for await (const el of arr) {
setData((d) => [...d, el]);
}
})();
}, []);
return <div>{data}</div>;
}

function makeAsyncArray(arr, delay) {
return {
[Symbol.asyncIterator]() {
let i = 0;
return {
next() {
const done = i === arr.length - 1;
const value = done ? undefined : arr[i];
i++;
return new Promise((res) =>
setTimeout(() => res({ value, done }), delay)
);
},
return() {
// This will be reached if the consumer called 'break' or 'return' early in the loop.
return { done: true };
},
};
},
};
}

现场演示:https://stackblitz.com/edit/react-yie8pg

最新更新