CountDown

By Fangtai Dong
Picture of the author
Published on
image alt attribute

CountDown Functional Component

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

import { fontSizes, spacing } from '../utils/sizes'
import { colors } from '../utils/colors'

// This function converts minutes to milliseconds for internal timing.
const mins2ms = (min) => min * 1000 * 60

// This function formats the time to two digits to ensure visual consistency (for example, display "9" as "09")
const formatT = (time) => (time < 10 ? `0${time}` : time)

export const Countdown = ({ minutes = 0.1, isPaused, onProgress, onEnd }) => {
  // use Ref to track the value of setInterval so that when I want to pause the time I can clear it.
  const interval = React.useRef(null)

  const [millis, setMillis] = useState(null)

  const countDown = () => {
    // This callback function in setMillis ensure that time is always the PREVIOUS STATE!
    setMillis((time) => {
      if (time === 0) {
        clearInterval(interval.current)
        onEnd()
        return time
      }
      const timeLeft = time - 1000

      // This is what going to be set to new millis state!
      return timeLeft
    })
  }

  useEffect(() => {
    setMillis(mins2ms(minutes))
  }, [minutes])

  useEffect(() => {
    onProgress(millis / mins2ms(minutes))
  }, [millis])

  useEffect(() => {
    if (isPaused) {
      if (interval.current) clearInterval(interval.current)
      return
    }
    // every 1 second, call the countDown Function
    interval.current = setInterval(countDown, 1000)

    // If I remove the component from screen, I will clear the interval completely and it is safety for the memory
    return () => clearInterval(interval.current)
  }, [isPaused])

  /**
   * Millis / 1000: First, divide the total number of milliseconds by 1000 to get the total number of seconds.
   * / 60: Then, divide the total number of seconds by 60 to get the total number of minutes (but this may be a decimal).
   * Math.floor(...): Using the Math.floor function, you can remove the decimal part of the obtained decimal number and keep only the integer part, that is, the actual complete number of minutes.
   * % 60: Finally, we perform the modulus 60 operation (taking remainder) for the number of minutes, so that we can get the remaining minutes in an hour. This is necessary, because there are 60 minutes in an hour, and what we need is the rest of an hour.
   */
  const minute = Math.floor(millis / 1000 / 60) % 60
  const seconds = Math.floor(millis / 1000) % 60

  return (
    <Text style={styles.text}>
      {/* Render formatted minutes and seconds LEFT! */}
      {formatT(minute)}:{formatT(seconds)}
    </Text>
  )
}

const styles = StyleSheet.create({
  text: {
    //...
  },
})

Hi there! Want to support my work?

© 2023 Fangtai Dong. All rights reserved.