gpt4 book ai didi

javascript - 在几秒钟内逐渐更新状态

转载 作者:行者123 更新时间:2023-11-29 15:08:28 25 4
gpt4 key购买 nike

我正在尝试模拟在网络应用程序上运行的脚本。这个想法是脚本在后台运行并启动 http 请求,然后这些请求应显示为 <p>。在一个分区中。但我不想让它走得太快。首先,状态更新太快不能正确更新,其次用户很难看到。

我试过使用 setTimeout,但这不起作用,因为它似乎设置了超时,然后继续 setState 而不等待。

AddParagraph = () => {

for(var i = 0; i < 20; i++){
setTimeout(function(){
this.setState({
urls: [...this.state.urls, www.url.com/i]
})},2000)
}
}

我读到在 for 循环中设置状态不是一个好主意,因为它没有时间快速渲染/更新。但是我看不出这样做的好主意,我不应该为此使用状态吗?

最佳答案

您似乎想要添加请求的 URL 并将其记录在网页上。

因此,您似乎对使用 for 更新状态“强制”感到困惑循环。
React 在本质上更像是一种声明,您的组件通常会对“状态”变化使用react。

所以不用 setTimeout ,这需要使用 for循环,让我们以设定的时间间隔对状态变化做出“ react ”。

类组件 (CC) 版本

如我所见this.state ,我假设您使用的是 CC。

class ClassRequestViewer extends Component {
state = {
urls: [],
postId: 1
};

// To be used to clear the interval
// 👇 to prevent memory leaks
intervalId = undefined;

// Add a paragraph while setting the new post ID
// 👇 together in one shot.
addParagraph = () => {
const newUrl = `${urlRoot}/${this.state.postId}`;
this.setState(prevState => ({
urls: prevState.urls.concat(newUrl),
postId: prevState.postId + 1
}));
};

// 👇 You would want to initialize the interval only ONCE
// as the changing the state in `addParagraph` will
// cause `ClassRequestViewer` to re-render (in `render()` below).
componentDidMount() {
this.intervalId = setInterval(this.addParagraph, timeout);
}

// ⚠👇 is important!
// We need to make sure to clean up to prevent memory leak.
// OR else, the interval will run even if the component is unmounted
// and unavailable.
componentWillUnmount() {
this.intervalId && clearInterval(this.intervalId);
}

// 👇 Whenever "addParagraph" updates the state,
// This gets called, so will show the requests sent automatically.
render() {
const { urls } = this.state;

return (
<ul style={{ listStyle: "none" }}>
{urls.map(url => (
<li key={url}>Request sent to {url}</li>
))}
</ul>
);
}
}

现在您可以看到以给定时间间隔发送以呈现的请求列表。

working demo

您可以在 CodeSandbox 上跟进
Edit so.answer.57364530


函数组件 (FC) 版本

我还在下面的 FC 中使用 Hook (useStateuseEffect)实现了相同的 CC 版本。

代码看起来更小为 useEffect有效地将关注点(setIntervalclearInterval)“共同定位”在一个地方。

function RequestViewer() {
const [urls, setUrls] = useState([]);
const [postId, setPostId] = useState(1);

useEffect(() => {
function addParagraph() {
const newUrl = `${urlRoot}/${postId}`;
setUrls(_ => _.concat(newUrl));
setPostId(postId + 1);
}

const intervalId = setInterval(addParagraph, timeout);
return () => clearInterval(intervalId);
}, [postId]);

return (
<ul style={{ listStyle: "none" }}>
{urls.map(url => (
<li key={url}>Request sent to {url}</li>
))}
</ul>
);
}

没有for在那里循环,因为useEffect每当 postId 时更新改变了,这是每个 timeoutsetInterval .


I want it to be started on an onClick event and stopped after X amount of rows. This seems to run endlessly?

正如您在 comment 中提到的那样, 它连续运行。
为了能够“开始/结束”该过程,您需要将“查看器”保留为查看器并处理父级上的显示。

因此,当您“启动”该过程时,查看器 ClassRequestViewer将启动请求并向您显示结果,然后单击“停止”将卸载组件(这就是我使用 componentWillUnmountclearInterval 的原因)。

我已经更新了 Appstart/stop按钮。

function App() {
const [isStarted, setIsStarted] = useState(false);

return (
<div className="App">
<h1>Request Viewer</h1>

{!isStarted && (
<button onClick={() => setIsStarted(true)}>Start the request</button>
)}
{isStarted && (
<>
<button onClick={() => setIsStarted(false)}>Stop Requests</button>
<ClassRequestViewer />
</>
)}
</div>
);
}

当您点击 Start the request 时按钮,它设置isStartedtrue ,因此 ClassRequestViewer已加载,您可以看到请求。

下面的代码已加载

{isStarted && (
<>
<button onClick={() => setIsStarted(false)}>Stop Requests</button>
<ClassRequestViewer />
</>
)}

当您点击 Stop Request 时按钮,设置isStartedfalse ,因此,ClassRequestViewer卸载,(依次调用 componentWillUnmount -> clearInterval 进行清理)。

然后你会看到 Start the request再次按钮。

{!isStarted && (
<button onClick={() => setIsStarted(true)}>Start the request</button>
)}

下面是更新后的 App 的工作演示.

start stop buttons

关于javascript - 在几秒钟内逐渐更新状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57364530/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com