2 回答
TA贡献1776条经验 获得超12个赞
您似乎想添加请求的 URL 并将其记录在网页上。
因此,您似乎对使用for循环“强制”更新状态感到困惑。
React 本质上更像是一种声明性的,您的组件通常会对“状态”变化做出反应。
因此setTimeout,与其使用需要使用for循环的 using ,不如让我们在设定的时间间隔内对状态变化做出“反应”。
类组件 (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>
);
}
}
现在您可以看到在给定时间间隔内发送到渲染的请求列表。
功能组件 (FC) 版本
我还在下面的 FC 中使用钩子 ( useState, useEffect)实现了相同的 CC 版本。
代码看起来更小,因为在一个地方useEffect有效地“共同定位”关注点 ( setInterval& clearInterval)。
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被改变,这是每一个timeout在几秒钟setInterval。
我希望它在 onClick 事件上启动并在 X 行后停止。这似乎无休止地运行?
正如您在评论中提到的,它会持续运行。
为了能够“开始/顶部”该过程,您将“查看器”作为查看器并处理父级上的显示。
所以,当你的“开始”的过程中,观众ClassRequestViewer将启动该请求,并显示你的结果,并在“STOP”将卸载的组件点击(这就是为什么我使用componentWillUnmount到clearInterval)。
我已经更新了App有start/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按钮时,它设置isStarted为true,从而ClassRequestViewer加载,您可以看到请求。
下面的代码已加载
{isStarted && (
<>
<button onClick={() => setIsStarted(false)}>Stop Requests</button>
<ClassRequestViewer />
</>
)}
当您单击Stop Request按钮时,该按钮设置isStarted为false,从而ClassRequestViewer卸载(反过来调用componentWillUnmount -> clearInterval清理)。
然后你会Start the request再次看到按钮。
{!isStarted && (
<button onClick={() => setIsStarted(true)}>Start the request</button>
)}
下面是更新的App.
添加回答
举报