Home > other >  react native interval problems
react native interval problems

Time:10-16

Hi i'm still pretty new to react native and i'm building a small app with a countdown. i'm pretty desperate and just don't understand what i should do to fix the problem. it's like this i have a button that when pressed should count down from the seconds set in settings to the format 00:00:00 it actually works pretty well at first but as soon as i try to stop the countdown again via the button or it turns by itself then it doesn't work properly anymore and counts down incorrectly does anyone know where the problem is and how i can fix this My Code:

when I click on the button then I run this code:

const sendData = () => {
setSendState(!sendState);

var seconds = state.count;
console.log('Seconds '   state.count);
if (sendState) {
  clearInterval(intervalId);
  setIntervalId(0);
  return;
}

the countdown interval:

const newIntervalId = setInterval(() => {
  
  let days = Math.floor(seconds / 24 / 60 / 60);
  let hoursLeft = Math.floor(seconds - days * 86400);
  let hours = Math.floor(hoursLeft / 3600);
  let minutesLeft = Math.floor(hoursLeft - hours * 3600);
  let minutes = Math.floor(minutesLeft / 60);
  let remainingSeconds = seconds % 60;
  let newpoutn;
  let percent = (remainingSeconds * 1000) / 100;
  setProgress(percent);
  const pad = n => {
    return n < 10 ? '0'   n : n;
  };
  setTime(`${pad(hours)}:${pad(minutes)}:${pad(remainingSeconds)}`);
  if (seconds == 0) {
    clearInterval(intervalId);
    setIntervalId(0);
    setSendState(false);
    return;
  } else {
    seconds--;
  }
}, 1000);
setIntervalId(newIntervalId);
clearInterval(intervalId);

};

CodePudding user response:

I normally store my interval ids with a useRef to avoid having to deal with re-rendering causing issues. Not sure if its necessary, but I dont run into issues when I do it that way. I also normally have a boolean state variable for toggling the interval on and off, that I listen to with an useEffect

import React, { useState, useRef, useEffect } from 'react';
import { Text, View, StyleSheet, Switch, Button } from 'react-native';
import Constants from 'expo-constants';

const secondRatios = {
  minute: 60,
  hour: 3600,
  day: 3600 * 24,
};
const formatSeconds = (s) => {
  const days = Math.floor(s / secondRatios.day)
    .toString()
    .padStart(2, '0');
  const hours = Math.floor(s / secondRatios.hour)
    .toString()
    .padStart(2, '0');
  const minutes = Math.floor(s / secondRatios.minute)
    .toString()
    .padStart(2, '0');
  const seconds = (s % 60).toString().padStart(2, '0');
  return `${days}:${hours}:${minutes}:${seconds}`;
};
const targetSeconds = 10;

export default function App() {
  // im not sure what you are using sendState for,
  // but im using it as marker of whether the interval
  // is running 
  const [sendState, setSendState] = useState(true);
  const [seconds, setSeconds] = useState(targetSeconds);
  const [progress, setProgress] = useState(0);
  const intervalId = useRef(null);
  const startInterval = () => {
    console.log('starting interval');
    intervalId.current = setInterval(() => {
      // im using the function form of the setter
      // because using seconds was providing stale values
      setSeconds((prev) => {
        let s = prev - 1;
        setProgress((targetSeconds - s) / targetSeconds);
        if (s <= 0) setSendState(false);
        return s;
      });
    }, 1000);
  };
  // interval operation is now directly linked to sendState
  useEffect(() => {
    if (sendState) startInterval();
    else clearInterval(intervalId.current);
  }, [sendState]);
 
  return (
    <View style={styles.container}>
      <Text style={styles.paragraph}>{(progress * 100).toFixed(2)}%</Text>
      <Text style={styles.text}>{formatSeconds(seconds)}</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    paddingTop: Constants.statusBarHeight,
    backgroundColor: '#ecf0f1',
    padding: 8,
  },
  paragraph: {
    margin: 24,
    fontSize: 18,
    fontWeight: 'bold',
    textAlign: 'center',
  },
  text: {
    textAlign: 'center',
    fontSize: 18,
  },
});

An expo snack

  • Related