Javascript 如何设置;间隔id“;表示反应

Javascript 如何设置;间隔id“;表示反应,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,我正在尝试创建一个允许创建计时器列表的应用程序。每个计时器都可以暂停和恢复 const [time, setTime] = useState({ hours: 0, minutes: 0, seconds: 1 }); useEffect(() => { const tick = () => { const duration = moment.duration( moment.duration((moment().format('X'

我正在尝试创建一个允许创建计时器列表的应用程序。每个计时器都可以暂停和恢复

const [time, setTime] = useState({ hours: 0, minutes: 0, seconds: 1 });

useEffect(() => {
    const tick = () => {
        const duration = moment.duration(
            moment.duration((moment().format('X') - data.unix) * 1000, 'milliseconds') + 1000,
            'milliseconds'
        );
        setTime({ hours: duration.hours(), minutes: duration.minutes(), seconds: duration.seconds() });
    };

    const timer = setInterval(tick, 1000);

    return () => {
        clearInterval(timer);
    };
}, [data.unix]);

这就是我现在所拥有的,我正在尝试做一个暂停选项,我认为可以通过清除interval来停止计时器来实现。但计时器在useEffect范围内,无法访问以删除useEffect之外的内容。如果我将计时器置于setState,则会导致错误。有什么建议吗?

为了在
useffect
之外保持对间隔的引用,您应该使用
useRef

这将允许清除事件处理程序上的间隔,例如:onClick

const IntervalComponent = (props) => {

    const intervalRef = useRef();
    
    
    useEffect(() => {
              intervalRef.current = getInterval();
            return () => clearInterval(intervalRef.current);
          }, []);
        
        const getInterval = () => {
            const startTime = new Date().getTime();
            const progressInterval = setInterval(() => {
              // do on each interval
            }, 10);
            return progressInterval;
          };

    
    const onClickHandler = (e) => clearInterval(intervalRef.current);

    return <button onClick={onClickHandler}>Clear interval</button> ;
}
const IntervalComponent=(道具)=>{
const intervalRef=useRef();
useffect(()=>{
intervalRef.current=getInterval();
return()=>clearInterval(intervalRef.current);
}, []);
常量getInterval=()=>{
const startTime=new Date().getTime();
const progressInterval=setInterval(()=>{
//在每一个时间间隔做什么
}, 10);
返回间隔;
};
const onClickHandler=(e)=>clearInterval(intervalRef.current);
返回清除间隔;
}

为了在
useffect
之外保持对间隔的引用,您应该使用
useRef

这将允许清除事件处理程序上的间隔,例如:onClick

const IntervalComponent = (props) => {

    const intervalRef = useRef();
    
    
    useEffect(() => {
              intervalRef.current = getInterval();
            return () => clearInterval(intervalRef.current);
          }, []);
        
        const getInterval = () => {
            const startTime = new Date().getTime();
            const progressInterval = setInterval(() => {
              // do on each interval
            }, 10);
            return progressInterval;
          };

    
    const onClickHandler = (e) => clearInterval(intervalRef.current);

    return <button onClick={onClickHandler}>Clear interval</button> ;
}
const IntervalComponent=(道具)=>{
const intervalRef=useRef();
useffect(()=>{
intervalRef.current=getInterval();
return()=>clearInterval(intervalRef.current);
}, []);
常量getInterval=()=>{
const startTime=new Date().getTime();
const progressInterval=setInterval(()=>{
//在每一个时间间隔做什么
}, 10);
返回间隔;
};
const onClickHandler=(e)=>clearInterval(intervalRef.current);
返回清除间隔;
}

我制作了这种工作示例(使用RN,但逻辑保持不变)。我嘲笑了时刻库的功能:

正如在已经投票的答案中所解释的,在使用
useffect
和间隔时,需要使用
useRef

核心功能:

const App = () => {
  let timer = useRef();
  const [time, setTime] = useState({ hours: 0, minutes: 0, seconds: 1 });
  const [toggleLabel, setToggleLabel] = useState('Pause');
  const tick = useCallback(() => {
    // mock:
    const duration = {
      hours: () => '0'.padStart(2, '0'),
      minutes: () => '0'.padStart(2, '0'),
      seconds: () => (''+ Math.floor(Math.random() * 60)).padStart(2, '0'),
    };

    setTime({
      hours: duration.hours(),
      minutes: duration.minutes(),
      seconds: duration.seconds(),
    });
  }, []);

  const startTicking = () => setInterval(tick, 1e3);
  const stopTicking = () => clearInterval(timer.current);

  const toggleTimer = () => {
    const shouldPause = (toggleLabel === 'Pause');
    timer.current = shouldPause ? stopTicking() : startTicking();
    setToggleLabel(shouldPause ? 'Resume' : 'Pause');
  };

  useEffect(() => {
    timer.current = startTicking();

    return () => {
      stopTicking();
    };
  }, [tick]);

  const { hours, minutes, seconds} = time;
  return (
    <View style={styles.container}>
      <Text>{`${hours}:${minutes}:${seconds}`}</Text>
      <TouchableOpacity style={styles.toggleButton} onPress={toggleTimer}><Text>{toggleLabel}</Text></TouchableOpacity>
    </View>
  );
};
const-App=()=>{
让timer=useRef();
const[time,setTime]=useState({hours:0,minutes:0,seconds:1});
常量[toggleLabel,setToggleLabel]=useState('Pause');
const tick=useCallback(()=>{
//模拟:
常数持续时间={
小时数:()=>“0”。padStart(2,“0”),
分钟数:()=>“0”。padStart(2,“0”),
秒:()=>(''+Math.floor(Math.random()*60)).padStart(2,'0'),
};
设定时间({
小时数:持续时间。小时数(),
分钟:持续时间。分钟(),
秒:持续时间。秒(),
});
}, []);
常量starttick=()=>setInterval(勾号,1e3);
const stopTicking=()=>clearInterval(timer.current);
常量切换计时器=()=>{
const shouldPause=(toggleLabel=='Pause');
timer.current=shouldPause?stoppticking():startTicking();
setToggleLabel(应暂停?'Resume':'Pause');
};
useffect(()=>{
timer.current=startTicking();
return()=>{
停止滴答声();
};
},[勾选];
常数{小时,分钟,秒}=时间;
返回(
{${hours}:${minutes}:${seconds}}}
{切换标签}
);
};

我制作了这种工作示例(使用RN,但逻辑保持不变)。我嘲笑了时刻库的功能:

正如在已经投票的答案中所解释的,在使用
useffect
和间隔时,需要使用
useRef

核心功能:

const App = () => {
  let timer = useRef();
  const [time, setTime] = useState({ hours: 0, minutes: 0, seconds: 1 });
  const [toggleLabel, setToggleLabel] = useState('Pause');
  const tick = useCallback(() => {
    // mock:
    const duration = {
      hours: () => '0'.padStart(2, '0'),
      minutes: () => '0'.padStart(2, '0'),
      seconds: () => (''+ Math.floor(Math.random() * 60)).padStart(2, '0'),
    };

    setTime({
      hours: duration.hours(),
      minutes: duration.minutes(),
      seconds: duration.seconds(),
    });
  }, []);

  const startTicking = () => setInterval(tick, 1e3);
  const stopTicking = () => clearInterval(timer.current);

  const toggleTimer = () => {
    const shouldPause = (toggleLabel === 'Pause');
    timer.current = shouldPause ? stopTicking() : startTicking();
    setToggleLabel(shouldPause ? 'Resume' : 'Pause');
  };

  useEffect(() => {
    timer.current = startTicking();

    return () => {
      stopTicking();
    };
  }, [tick]);

  const { hours, minutes, seconds} = time;
  return (
    <View style={styles.container}>
      <Text>{`${hours}:${minutes}:${seconds}`}</Text>
      <TouchableOpacity style={styles.toggleButton} onPress={toggleTimer}><Text>{toggleLabel}</Text></TouchableOpacity>
    </View>
  );
};
const-App=()=>{
让timer=useRef();
const[time,setTime]=useState({hours:0,minutes:0,seconds:1});
常量[toggleLabel,setToggleLabel]=useState('Pause');
const tick=useCallback(()=>{
//模拟:
常数持续时间={
小时数:()=>“0”。padStart(2,“0”),
分钟数:()=>“0”。padStart(2,“0”),
秒:()=>(''+Math.floor(Math.random()*60)).padStart(2,'0'),
};
设定时间({
小时数:持续时间。小时数(),
分钟:持续时间。分钟(),
秒:持续时间。秒(),
});
}, []);
常量starttick=()=>setInterval(勾号,1e3);
const stopTicking=()=>clearInterval(timer.current);
常量切换计时器=()=>{
const shouldPause=(toggleLabel=='Pause');
timer.current=shouldPause?stoppticking():startTicking();
setToggleLabel(应暂停?'Resume':'Pause');
};
useffect(()=>{
timer.current=startTicking();
return()=>{
停止滴答声();
};
},[勾选];
常数{小时,分钟,秒}=时间;
返回(
{${hours}:${minutes}:${seconds}}}
{切换标签}
);
};