【问题标题】:Using timer/interval in a Function Component (React) vs Component在函数组件(React)与组件中使用计时器/间隔
【发布时间】:2021-04-17 19:37:10
【问题描述】:

以下 sn-p 演示了在 React 功能组件中使用的 javascript 计时器或间隔的行为与使用类 React 组件时的行为不同。 另外,我看到了不同的行为。就像混乱的执行而不是指定的时间一样。

有解决办法吗?因为我不喜欢回到 Component 并且不再(或几乎不)能够使用钩子了。

https://jsfiddle.net/L5mbqsk9/1/


const App = ()=>{
  const [count, setCount] = React.useState(0);
  const myfunc = ()=>{
    setCount(count+1);
  }
  React.useEffect(()=>{
    const tmr = setInterval(myfunc, 1000);
   return () => clearInterval(tmr);
  }, [])
  return (
    <div className="App">
      <h1>app</h1>
      {count}
    </div>
  );
}

class App2 extends React.Component
{
  constructor(props) {
    super(props);
    this.state = { count: 0 };
    this.tmr = {};
  }
  myfunc = () => {
    this.setState({ count: this.state.count + 1 });
  }
  tmr;

  componentDidMount() {
    this.tmr = setInterval(this.myfunc, 1000);

  }
  componentWillUnmount() {
    clearInterval(this.tmr);
  }

  render() {
    return (
      <div className="App">
        <h1>App2</h1>
        {this.state.count}
      </div>
    );
  }
}


ReactDOM.render(
        <div>
      <div><App /></div>
      <div><App2/></div>
    </div>,
  document.getElementById('container')
);
```

【问题讨论】:

    标签: reactjs settimeout setinterval


    【解决方案1】:

    您当前的功能组件只运行一次效果,因为您已将一个空的依赖数组传递给效果挂钩。效果关闭count 的第一个值0,并将其设置为1

    如果您只想在效果中仅根据之前的状态更新状态,您只需将函数而不是值传递给setCount

    const App = () => {
      const [count, setCount] = React.useState(0);
    
      React.useEffect(() => {
        const tmr = setInterval(() => setCount(c => c+1), 1000);
       return () => clearInterval(tmr);
      }, []);
    
      return (
        <div className="App">
          <h1>app</h1>
          {count}
        </div>
      );
    }
    

    但是,对于更一般的用例,如果您想在效果内使用间隔/超时,则需要将依赖数组传递给您在内部使用的所有值的效果挂钩 - 在本例中为 [count],因为您通过myfunc 使用它(间接)。这是一个示例:

    const App = () => {
      const [count, setCount] = React.useState(0);
      const myfunc = () => {
        setCount(count+1);
      };
    
      React.useEffect(() => {
        const tmr = setInterval(myfunc, 1000);
       return () => clearInterval(tmr);
      }, [count]);
    
      return (
        <div className="App">
          <h1>app</h1>
          {count}
        </div>
      );
    }
    

    请注意,由于这个原因,间隔计时器将每秒设置和清除一次,因此您应该可以只使用 setTimeout 代替。如果您不希望效果在每次更新时清除计时器/间隔,您可以考虑使用更详细的方法,使用ref hooks 来存储状态变量并从计时器效果访问ref,而不是状态。

    【讨论】:

    • 很好的反馈。工作。
    【解决方案2】:

    答案已更新:问题出在您的状态更新函数中 我已经用你的小提琴演奏了 10 分钟,发现它工作正常。检查此解决方法

    const App = () => {
      const [count, setCount] = React.useState(0);
      React.useEffect(() => {
        const myfunc = () => {
          setCount(prevCount => prevCount + 1);
        }
        const tmr = setInterval(myfunc, 1000);
        return () => clearInterval(tmr);
      }, [])
      return (
        <div className="App">
          <h1>Functional Component</h1>
          {count}
        </div>
      );
    }
    class App2 extends React.Component {
      constructor(props) {
        super(props);
        this.state = { count: 0 };
        this.tmr = {};
      }
      myfunc = () => {
        this.setState((prevState) => {
            return {count: prevState.count + 1}
        })
      }
      componentDidMount() {
        this.tmr = setInterval(this.myfunc, 1000);
      }
      componentWillUnmount() {
        clearInterval(this.tmr);
      }
      render() {
        return (
          <div className="App">
            <h1>Class Component</h1>
            {this.state.count}
          </div>
        );
      }
    }
    ReactDOM.render(
      <div>
        <div><App /></div>
        <div><App2/></div>
      </div>,
      document.getElementById('container')
    );
    

    如果新状态是使用先前状态计算的,则使用 setState 的功能更新形式,即 setCount(c =&gt; c + 1) 而不是 setCount(count + 1) 。检查https://reactjs.org/docs/hooks-faq.html#what-can-i-do-if-my-effect-dependencies-change-too-often

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-15
      • 1970-01-01
      • 2020-10-23
      • 2021-11-18
      • 1970-01-01
      • 2021-01-10
      相关资源
      最近更新 更多