在函数组件 (React) 与组件中使用计时器/间隔

时间:2021-04-17 19:37:10

标签: reactjs settimeout setinterval

以下代码片段演示了在 React 功能组件中使用的 javascript 计时器或间隔的行为与使用类 React 组件时的行为不同。 此外,我还看到了不同的行为。像混乱的执行而不是指示的时间。

是否有解决方法?因为我不喜欢回到 Component 并且不再(或几乎)无法使用 hooks。

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')
);
```

2 个答案:

答案 0 :(得分:1)

答案已更新:问题出在您的状态更新程序功能中 我已经用你的小提琴演奏了 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 => c + 1) 而不是 setCount(count + 1) 。检查https://reactjs.org/docs/hooks-faq.html#what-can-i-do-if-my-effect-dependencies-change-too-often

答案 1 :(得分: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 的更详细的方法,而不是国家。