【问题标题】:React: For Loop is not detecting Hook's State changes反应:For Loop 没有检测到 Hook 的状态变化
【发布时间】:2021-08-09 02:44:36
【问题描述】:

开发一个 React 应用程序,其主要功能是在用户预先设置的时间间隔内显示句子的每个单词(基本上是快速阅读)。几天前我实现了这一点,但现在我尝试实现一个暂停按钮(暂停循环并获取实际单词)并卡住了。

我决定添加一个暂停按钮,它调用一个将暂停状态设置为真的函数,在我的循环中,如果这个暂停状态为“真”,它就会跳出循环。但问题是,这个循环没有检测到变化,我在第 18 行有一个 console.log,它总是记录为假,尽管我已经点击了暂停按钮并将状态更改为“假”(这正在工作因为我也将它记录在 useEffect 和它的登录 'true')

所以,我的问题是,我该如何解决这个问题?我是不是用错了 react hooks?

代码示例:

const [time, setTime] = React.useState('500')
const [pause, setPause] = React.useState(false)
const go = async function(){
    let textarray = text.split(' ') //I split my text 
    for(let i = 0; i < textarray.length; i++){ 
        console.log(pause) //This keeps logging false although the change in pauseButton function
        if(pause){
            //Get the actual word => i
            break;
        }
        else{
            setValue(textarray[i]) //Show the actual word
            await timeout(time) //Wait the time
        }
    }
}
const pauseButton = function(){
    setPause(true)
}
function timeout(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

【问题讨论】:

    标签: javascript reactjs react-hooks


    【解决方案1】:

    我想你可能想稍微重构一下。考虑设置useInterval() hook 来运行计数器。然后就很容易启动和停止您的计数器。

    使用 useMemo 钩子来分割 textArray 的结果,所以它不会重新计算每次刷新。

    然后你可以随时获取 textarray[i] 的值并放入你的 JSX。

    这样你就不需要任何其他异步函数了。

    【讨论】:

    • 好的,我会尝试使用这个 Hook,感谢您的回复。所以这里的问题是异步函数?我怎样才能暂停这个 useInterval() Hook?再次感谢!
    • React 组件不是天生的“程序化”组件,因为您通常不会在它们显示后更改它们。通常最容易将它们视为接收数据。也许做一些计算;然后返回显示组件。当然,这并不总是正确的。您可以从 API 执行异步获取,或者在这种情况下设置一个计时器。但是设置一个计时器比你想象的要复杂,因为它只是帮助使用一个基于 useInterval 之类的简单计时器,然后想象每个“滴答”你正在使用新数据重新渲染组件。
    • 我在答案中的链接有一个很好的例子——超级简单。它设置了一个计数器,这也是你所需要的。
    【解决方案2】:

    基本上,您不了解 javascript 闭包,因此这就是您在 async 函数的上下文中错误地使用钩子的原因。您无法以实用的方式在异步函数中获取状态更新。您应该使用 useEffects 或自定义挂钩 (Live demo to play):

    import React from "react";
    import { useState } from "react";
    import { useAsyncCallback } from "use-async-effect2";
    import { CPromise } from "c-promise2";
    
    function TestComponent(props) {
      const [text, setText] = useState("one two three four five");
      const [word, setWord] = useState("");
    
      const go = useAsyncCallback(
        function* (text, delay) {
          const words = text.split(/\s+/);
          for (const word of words) {
            setWord(word);
            yield CPromise.delay(delay);
          }
        },
        { states: true, cancelPrevios: true }
      );
    
      return (
        <div className="component">
          <div className="caption">useAsyncEffect demo</div>
          <input
            value={text}
            onChange={({ target }) => {
              setText(target.value);
            }}
          />
          <div>{go.error ? go.error.toString() : word}</div>
          {go.pending ? (
            go.paused ? (
              <button className="btn btn-warning" onClick={go.resume}>
                Resume
              </button>
            ) : (
              <button className="btn btn-warning" onClick={go.pause}>
                Pause
              </button>
            )
          ) : (
            <button className="btn btn-warning" onClick={() => go(text, 1000)}>
              Run
            </button>
          )}
          {go.pending && (
            <button className="btn btn-warning" onClick={go.cancel}>
              Cancel request
            </button>
          )}
        </div>
      );
    }
    

    【讨论】:

      猜你喜欢
      • 2021-06-03
      • 2021-04-17
      • 1970-01-01
      • 2021-10-31
      • 2022-06-21
      • 2017-06-24
      • 1970-01-01
      • 1970-01-01
      • 2021-09-22
      相关资源
      最近更新 更多