为了账号安全,请及时绑定邮箱和手机立即绑定

在几秒钟内逐渐更新状态

在几秒钟内逐渐更新状态

侃侃无极 2021-09-04 17:33:37
我正在尝试模拟在 Web 应用程序上运行的脚本。这个想法是一个脚本在后台运行并启动 http 请求,然后这些请求应该显示为<p>一个 div。但我不希望它走得太快。一是状态更新太快,更新不正确,二是让用户难以看到。我曾尝试使用 setTimeout,但这不起作用,因为它似乎正在设置超时,然后继续 setState 而无需等待。AddParagraph = () => {for(var i = 0; i < 20; i++){ setTimeout(function(){ this.setState({    urls: [...this.state.urls, www.url.com/i] })},2000) }}我已经读过在 for 循环中设置状态不是一个好主意,因为它没有时间那么快地呈现/更新。但是我认为这样做不是一个好主意,我不应该为此使用状态吗?
查看完整描述

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>

    );

  }

}

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

//img1.sycdn.imooc.com//61333d9e00012a9400010001.jpg

功能组件 (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.

//img1.sycdn.imooc.com//61333db5000128b800010001.jpg

查看完整回答
反对 回复 2021-09-04
  • 2 回答
  • 0 关注
  • 154 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信