如何使用`onClick`事件停止调用useEffect挂钩所调用的函数?

时间:2020-04-17 14:36:53

标签: reactjs react-hooks setinterval clearinterval use-effect

如何使用onClick事件来停止重复发生的函数调用?由于使用了useEffectsetIntervalclearInterval,因此函数调用重复进行。

this article中所示的示例,以下代码将永远运行。一旦单击<header></header>,如何停止调用该函数?

import React, { useState, useEffect } from 'react';

const IntervalExample = () => {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setSeconds(seconds => seconds + 1);
    }, 1000);
    return () => clearInterval(interval);
  }, []);

  return (
    <div className="App">
      <header className="App-header">
        {seconds} seconds have elapsed since mounting.
      </header>
    </div>
  );
};

export default IntervalExample;

3 个答案:

答案 0 :(得分:1)

我会像这样从useEffect函数中拉出间隔const。

<div class="input-field col s12">
    <select id="country-list" onchange="changeCountry(this)">
        <option value="none" disabled selected>Choose your option</option>
        <option value="Ukraine">Ukraine </option>
        <option value="Poland">Poland</option>
    </select>
</div>

<div class="input-field col s12">
    <select id="city-list">
        <option value="none" disabled selected>Choose your option</option>
    </select>
</div>

答案 1 :(得分:1)

添加另一个名为running的状态,并使useEffect依赖于该状态。每当将running切换到false时,间隔就会由useEffect的清除功能清除。由于runningfalse,因此我们跳过设置新间隔的过程。每当将其切换为true时,它将重新启动。

const { useState, useEffect, useCallback } = React;

const IntervalExample = () => {
  const [seconds, setSeconds] = useState(0);
  const [running, setRunning] = useState(true);
  
  const toggleRunning = useCallback(
    () => setRunning(run => !run)
  , []);

  useEffect(() => {
    if(!running) {
      // setSeconds(0); // if you want to reset it as well
      return;
    }
    
    const interval = setInterval(() => {
      setSeconds(seconds => seconds + 1);
    }, 1000);
    return () => clearInterval(interval);
  }, [running]);

  return (
    <div className="App">
      <header className="App-header">
        {seconds} seconds have elapsed since mounting.
      </header>
      
      <button
        onClick={toggleRunning}
        >
        {running ? 'running' : 'stopped'}
      </button>
    </div>
  );
};

ReactDOM.render(
  <IntervalExample />,
  root
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

答案 2 :(得分:1)

我认为阻止您的意思是在点击事件中说clearInterval。因此,将间隔ID保留在新状态变量中的最佳方法。


const IntervalExample = () => {
  const [seconds, setSeconds] = useState(0);
  const [currentIntervalId, setIntervalId] = useState(null);

  useEffect(() => {
    const interval = setInterval(() => {
      setSeconds(seconds => seconds + 1);
    }, 1000);
    setIntervalId(interval);
    return () => clearInterval(interval);
  }, []);

  const stopInterval = () => {
    clearInterval(currentIntervalId);
  };

  return (
    <div className="App">
      <header className="App-header" onClick={stopInterval}>
        {seconds} seconds have elapsed since mounting.
      </header>
    </div>
  );
};
  • 为什么处于状态? 因为这将为您提供更大的灵活性,让您可以重新启动间隔或根据事件随时停止。

注意:您也可以将其放在useEffect范围之外定义的变量中。