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

标签 javascript reactjs state

我正在尝试模拟在网络应用程序上运行的脚本。这个想法是脚本在后台运行并启动 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/

相关文章:

reactjs - Redux 持续错误序列化 PeerJS 对象

javascript - 'componentDidMount' 生命周期方法不更新状态

javascript - react 没有在输入更改时更新功能组件状态

javascript - 子菜单动态宽度

java - Javascript 中的 GWT 自定义事件触发器

javascript - AngularJS - 表达式未在 HTML 中显示

javascript - 在 redux 中间件中调度多个操作

javascript - 在多个图像上使用相同的图像映射,但每个图像上的每个区域都有不同的链接

reactjs - 微前端基于 React/Component 的拆分

java - Apache Beam 中有状态处理的问题