如何使用 React Native 正确清除间隔

How to clearInterval correctly using React Native

在 RN 中,我有一个使用 setInterval 的倒数计时器,从 10 到 0。 一旦满足时间 === 0 或小于 1 的条件,我希望间隔停止。 倒计时正在工作但不断重复,clearInterval 不起作用。 我做错了什么?

import { StyleSheet, Text } from 'react-native'
import React, {useEffect, useState} from 'react'


export default function Timer() {
  const [time, setTime] = useState(10)

  useEffect(() => {
    if(time > 0) {
      var intervalID = setInterval(() => {
        setTime(time => time > 0 ? time - 1 : time = 10)
      }, 1000)
    } else {
      clearInterval(intervalID)
    } 
    }, [])  


  return <Text style={styles.timer}>{time}</Text>
}

函数在 useEffect 上,仅在组件为 mounted/unmounted 时执行,在函数执行的那一刻,时间为 10,因此永远不会进入 else 条件。

此代码一定适合您:


import { StyleSheet, Text } from 'react-native'
import React, {useEffect, useState} from 'react'


export default function Timer() {
  const [time, setTime] = useState(10)
  time <= 0 && clearInterval(intervalID)

  useEffect(() => {
      var intervalID = setInterval(() => {
        setTime(time => time > 0 ? time - 1 : time = 10)
      }, 1000)

      return () => {
        clearInterval(intervalID)
      }
    }, [])  


  return <Text style={styles.timer}>{time}</Text>

ClearInterval应该在setTime里面,因为useEffect只会触发一次

注意:您还应该在卸载时清除。

export default function Timer() {
  const [time, setTime] = useState(10);

  useEffect(() => {
    var intervalID = setInterval(() => {
      setTime((time) => {
        if (time > 0) {
          return time - 1;
        }
        clearInterval(intervalID);
        return time;
      });
    }, 1000);

    return () => clearInterval(intervalID);
  }, []);

  return <Text style={styles.timer}>{time}</Text>;
}

你也可以使用这个:

import React, { useEffect, useState, useRef } from 'react'
import { Text } from 'react-native'

const Timer = () => {
  const [time, setTime] = useState(10)
  const promiseRef = useRef(null)

  useEffect(() => {
    if(time > 0) {
      promiseRef.current = setInterval(() => {
        setTime(time => time > 0 ? time - 1 : time = 10)
      }, 1000)
    } else {
      promiseRef.current = null
    } 
  }, [])

  return <Text style={styles.timer}>{time}</Text>
}

export default Timer

您的 useEffect 在依赖项数组中没有任何值(时间),因此它 运行 只会在组件挂载时出现一次。

const [time, setTime] = useState(10);

useEffect(() => {
 if (time === 0) {
   return;
 }

 const timeoutId = setInterval(() => {
   setTime(time - 1);
 }, 1000);

 return () => {
   clearInterval(timeoutId);
 };
}, [time]);

您也可以使用超时,在这种情况下您不需要清除任何内容,因为它 运行 每个 useEffect 触发器只会执行一次。

useEffect(() => {
 if (time === 0) {
   return;
 }

 setTimeout(() => {
   setTime(time - 1);
 }, 1000);
}, [time]);

如果您不想将 time 添加到依赖项数组,另一个可能有效的选项是清除 setTime

中的间隔
 useEffect(() => {
 const intervalID = setInterval(() => {
   setTime((time) => {
     if (time === 0) {
       clearInterval(intervalID);

       return time;
     }

     return time - 1;
   });
 }, 1000);
 return () => {
   clearInterval(intervalID);
 };
}, []);

请注意,在您的示例中,您正在倒数到 1,然后倒数到 10,因此它永远不会达到 0

setTime(time => time > 0 ? time - 1 : time = 10)

如果你希望它在完成计数后重置回 10,最后一个选项可能适合你,因为它不会在每次更改时触发效果,只需要 return 10 而不是 time 清除间隔后 这是一个例子https://jsfiddle.net/dnyrm68t/