本机React倒计时器

1tu0hz3e  于 2023-01-14  发布在  React
关注(0)|答案(7)|浏览(163)

我想在react-native中加载一个屏幕时从3倒计时到1。我尝试使用setTimeOut这样做,但它不起作用。我在这里做错了什么?我如何实现这一点?当屏幕加载时,我想以1秒的间隔显示3 =-〉2 ==〉1。以下是我的代码。

constructor(props) {
        super(props);

        this.state = {
            timer: 3
        }
    }

    // componentDidMount 
    componentDidMount() {
        setTimeout(() => {
            this.setState({
                timer: --this.state.timer
            })
        }, 1000);
    }
ercv8c1e

ercv8c1e1#

在您的代码中,setTimeout在componentDidMount中调用,ComponetDidMount将在整个组件生命周期中调用一次。因此,setTimeout中的函数将仅调用一次。即,在第一次渲染之后,但在连续渲染时,将不会调用componentDidMount。
问题的解决方案可以是:

1.类组件

constructor(props: Object) {
  super(props);
  this.state ={ timer: 3}
}

componentDidMount(){
  this.interval = setInterval(
    () => this.setState((prevState)=> ({ timer: prevState.timer - 1 })),
    1000
  );
}

componentDidUpdate(){
  if(this.state.timer === 1){ 
    clearInterval(this.interval);
  }
}

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

render() {
  return (
    <View style={{ flex: 1, justifyContent: 'center', }}>
      <Text> {this.state.timer} </Text>
    </View> 
  )
}

'setInterval' vs 'setTimeout'
Advantage of using a function in setState instead of an object
memory leak because of setInterval:如果在调用clearInterval之前卸载组件,则会出现内存泄漏,因为启动时设置了间隔,但计时器未停止。React提供componentWillUnmount生命周期方法,以便在卸载或删除组件时清除任何需要清除的内容。

2.功能组件

function CountDownTimer(props) {
  const [time, setTime] = React.useState(props.initialValue || 10);
  const timerRef = React.useRef(time);

  React.useEffect(() => {
    const timerId = setInterval(() => {
      timerRef.current -= 1;
      if (timerRef.current < 0) {
        clearInterval(timerId);
      } else {
        setTime(timerRef.current);
      }
    }, 1000);
    return () => {
      clearInterval(timerId);
    };
  }, []);

  return ( 
    <View style={{ flex: 1, justifyContent: 'center' }}>
      <Text> {time} </Text>
    </View>
  )
}

useRef返回一个可变的ref对象,其.current属性被初始化为传递的参数(initialValue)。返回的对象将在组件的整个生存期内持续存在。因此,在组件重新呈现时,对象引用将相同。
@TheEhsanSarshar和@Rishabh Jain给出的答案也是可行的。我展示了一个与其他人略有不同的解决方案。

ncgqoxb0

ncgqoxb02#

使用react-native中的*setInterval*挂钩(使用useEffect)版本更新为倒计时

const [timerCount, setTimer] = useState(60)

useEffect(() => {
  let interval = setInterval(() => {
    setTimer(lastTimerCount => {
        lastTimerCount <= 1 && clearInterval(interval)
        return lastTimerCount - 1
    })
  }, 1000) //each count lasts for a second
  //cleanup the interval on complete
  return () => clearInterval(interval)
}, []);

使用状态变量 timerCount 作为:<Text>{timerCount}</Text>

gab6jxml

gab6jxml3#

    • 用法:**
  • 时间戳 * 属性必须以秒为单位
const refTimer = useRef();
  
  const timerCallbackFunc = timerFlag => {
    // Setting timer flag to finished
    console.warn(
      'You can alert the user by letting him know that Timer is out.',
    );
  };
    
    
 <Timer
 ref={refTimer}
 timestamp={moment(item?.time_left).diff(moment(), 'seconds')}
 timerCallback={timerCallbackFunc}
 textStyle={styles.timerTextAHL}
 />
    • 定时器. js**
import React, {
  useState,
  useEffect,
  useRef,
  forwardRef,
  useImperativeHandle,
} from 'react';
import { Text, View } from 'react-native';

const Timer = forwardRef((props, ref) => {
  // For Total seconds
  const [timeStamp, setTimeStamp] = useState(
    props.timestamp ? props.timestamp : 0,
  );
  // Delay Required
  const [delay, setDelay] = useState(props.delay ? props.delay : 1000);

  // Flag for informing parent component when timer is over
  const [sendOnce, setSendOnce] = useState(true);

  // Flag for final display time format
  const [finalDisplayTime, setFinalDisplayTime] = useState('');

  useInterval(() => {
    if (timeStamp > 0) {
      setTimeStamp(timeStamp - 1);
    } else if (sendOnce) {
      if (props.timerCallback) {
        props.timerCallback(true);
      } else {
        console.log('Please pass a callback function...');
      }
      setSendOnce(false);
    }
    setFinalDisplayTime(secondsToDhms(timeStamp));
  }, delay);

  function secondsToDhms(seconds) {
    seconds = Number(seconds);
    var d = Math.floor(seconds / (3600 * 24));
    var h = Math.floor((seconds % (3600 * 24)) / 3600);
    var m = Math.floor((seconds % 3600) / 60);
    var s = Math.floor(seconds % 60);

    var dDisplay = d > 0 ? d + 'd ' : '';
    var hDisplay = h > 0 ? h + 'h ' : '';
    var mDisplay = m > 0 ? m + 'm ' : '';
    var sDisplay = s > 0 ? s + 's ' : '';
    return dDisplay + hDisplay + mDisplay + sDisplay;
  }

  const refTimer = useRef();
  useImperativeHandle(ref, () => ({
    resetTimer: () => {
      // Clearing days, hours, minutes and seconds
      // Clearing Timestamp
      setTimeStamp(props.timestamp);
      setSendOnce(true);
    },
  }));

  return (
    <View ref={refTimer} style={props.containerStyle}>
      <Text style={props.textStyle}>{sendOnce ? finalDisplayTime : '0'}</Text>
    </View>
  );
});

function useInterval(callback, delay) {
  const savedCallback = useRef();

  // Remember the latest function.
  useEffect(() => {
    savedCallback.current = callback;
  }, [callback]);

  // Set up the interval.
  useEffect(() => {
    function tick() {
      savedCallback.current();
    }
    if (delay !== null) {
      const id = setInterval(tick, delay);
      return () => {
        clearInterval(id);
      };
    }
  }, [delay]);
}

export default Timer;

iecba09b

iecba09b4#

钩子版本

function CountDown() {
   const [count, setCount] = useState(3)

   useEffect(() => 
     let interval = setInterVal(() => {
        setCount(prev => {
           if(prev === 1) clearInterval(interval)
           return prev - 1
        })
     })
     // interval cleanup on component unmount
     return () => clearInterval(interval)
   ), [])

   return <Text>{count}</Text>
}
xurqigkl

xurqigkl5#

如果有人想在按下按钮时再次启动计时器,这将是react-hooks中的代码:

let timer = () => {};

const myTimer = () => {
    const [timeLeft, setTimeLeft] = useState(30);

    const startTimer = () => {
        timer = setTimeout(() => {
            if(timeLeft <= 0){
                clearTimeout(timer);
                return false;
            }
         setTimeLeft(timeLeft-1);
        }, 1000)
     }

     useEffect(() => {
         startTimer();
         return () => clearTimeout(timer);
     });    

    const start = () => {
        setTimeLeft(30);
        clearTimeout(timer);
        startTimer();
    }

    return (
       <View style={styles.container}>
          <Text style={styles.timer}>{timeLeft}</Text>
          <Button onPress={start} title="Press"/>
    </View>
)}

在本例中,我使用了30秒的计时器

wlp8pajw

wlp8pajw6#

下面是一个示例,说明如何创建倒计时计时器,以便倒计时到特定的UTC日期:

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

const CountdownTimer = () => {
  const [timeLeft, setTimeLeft] = useState<number>(0);

  const targetDate = new Date("2022-12-31T23:59:59Z").getTime();
  const currentDate = new Date().getTime();
  const distance = targetDate - currentDate;

  useEffect(() => {
    const intervalId = setInterval(() => {
      setTimeLeft(distance);
    }, 1000);
    return () => clearInterval(intervalId);
  }, []);

  let days = Math.floor(timeLeft / (1000 * 60 * 60 * 24));
  let hours = Math.floor((timeLeft % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
  let minutes = Math.floor((timeLeft % (1000 * 60 * 60)) / (1000 * 60));
  let seconds = Math.floor((timeLeft % (1000 * 60)) / 1000);

  return (
    <View>
      <Text>{days}d {hours}h {minutes}m {seconds}s</Text>
    </View>
  );
};

export default CountdownTimer;
u5i3ibmn

u5i3ibmn7#

电源代码希望这样的方式是容易的

componentDidMount() {
        this.CounterInterval()
  }
  CounterInterval = () => {
    this.interval = setInterval(
      () =>   this.setState({
        timer: this.state.timer - 1
      }, () => {
        if (this.state.timer === 0) {
          clearInterval(this.interval);
        }
      }),
      1000
    );
  }

相关问题