react-nativestopwatch

React Native stopwatch implementation slow on iOS


I have the following stopwatch implementation

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

function TimerComponent() {
  const [isActive, setIsActive] = useState(false);
  const [time, setTime] = useState(0);

  useEffect(() => {
    let interval = null;

    if (isActive) {
      interval = setInterval(() => {
        setTime(time => time + 0.1);
      }, 100);
    } else {
      clearInterval(interval);
    }
    return () => {
      clearInterval(interval);
    };
  }, [isActive]);

  const handleStart = () => {
    setIsActive(true);
  };

  const handleReset = () => {
    setIsActive(false);
    setTime(0);
  };

  const roundedTime = time.toFixed(1);

  return (
    <View style={styles.outerContainer}>
      <Button
        title="Start"
        onPress={handleStart}
      />
      <Text style={styles.text}>{roundedTime}</Text>
      <Button
        title="Stop"
        onPress={handleReset}
      />
    </View>
  );
}

export default TimerComponent;

on Android it works as expected, when I compare to another stopwatch it reaches 30 seconds at the same time, but when I test on iOS it takes around 5 seconds longer.


Solution

  • Don‘t use setTime(time => time + 0.1); to calculate the passed time. Rather use Date:

    const start = Date.now();
    
    console.log('starting timer...');
    // Expected output: "starting timer..."
    
    setTimeout(() => {
      const millis = Date.now() - start;
    
      console.log(`seconds elapsed = ${Math.floor(millis / 1000)}`);
      // Expected output: "seconds elapsed = 2"
    }, 2000);