clearInterval() 在 React Native 中不起作用 - 尝试从 class 转换为功能组件 - 计时器

clearInterval() not working in React Native - trying to convert from class to functional components - Timer

尝试在本机反应中制作秒表我有工作代码和class组件但是当尝试使用功能组件时clearInterval()函数没有'没工作

来自 ReactNativeAcademy/Stopwatch 的源代码在此处修改之前 https://github.com/ReactNativeAcademy/Stopwatch/blob/master/App.js

我只需要一个没有圈数的基本计时器,只有 start/resume/stop /重置 按钮 零食 url 我的代码:https://snack.expo.io/@mansouriala/nervous-mixed-nuts 为了在基于 class 的组件中对其进行测试,您可以在功能函数下找到每个基于 class 的函数。

我不知道,但也许一个解决方案是将 setInterval 包装在 useEffect 中,然后创建一个新的状态变量,在开始时将其切换为 true 并且 useEffect 侦听该变量。

事不宜迟,这里是代码:

import React, { Component, useEffect, useState } from 'react';
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
import moment from 'moment';

function Timer({ interval, style }) {
  const pad = (n) => (n < 10 ? `0${n}` : n);
  const duration = moment.duration(interval);
  const centiseconds = Math.floor(duration.milliseconds() / 10);

  return (
    <View style={styles.timerContainer}>
      <Text style={style}>{pad(duration.minutes())}:</Text>
      <Text style={style}>{pad(duration.seconds())},</Text>
      <Text style={style}>{pad(centiseconds)}</Text>
    </View>
  );
}

function RoundButton({ title, color, background, onPress }) {
  return (
    <TouchableOpacity onPress={onPress} style={[styles.button, { backgroundColor: background }]}>
      <View style={styles.buttonBorder}>
        <Text style={[styles.buttonTitle, { color }]}>{title}</Text>
      </View>
    </TouchableOpacity>
  );
}

function ButtonsRow({ children }) {
  return <View style={styles.buttonsRow}>{children}</View>;
}

// export default class App extends Component {
export default function App() {
  const [timer, setTimer] = useState(0);
  const [state, setState] = useState({
    start: 0,
    now: 0,
    currentTime: 0,
  });

  // constructor(props) {
  //   super(props);
  //   this.state = {
  //     start: 0,
  //     now: 0,
  //     currentTime: 0,
  //   };
  // }

  useEffect(() => {
    return () => {
      clearInterval(timer);
    };
  }, []);

  // componentWillUnmount() {
  //   clearInterval(this.timer);
  // }

  const startHandler = () => {
    const now = new Date().getTime();
    setState({
      start: now,
      now,
      currentTime: 0,
    });
    setInterval(
      setInterval(() => {
        setState((prev) => ({ ...prev, now: new Date().getTime() }));
      }, 100)
    );
  };

  // startHandler = () => {
  //   const now = new Date().getTime();
  //   this.setState({
  //     start: now,
  //     now,
  //     currentTime: 0,
  //   });
  //   this.timer = setInterval(() => {
  //     this.setState({ now: new Date().getTime() });
  //   }, 100);
  // };

  const stopHandler = () => {
    clearInterval(timer);
    const { currentTime, now, start } = state;
    setState((prev) => ({
      // ...prev,
      currentTime: currentTime + (now - start),
      start: 0,
      now: 0,
    }));
  };

  // stopHandler = () => {
  //   clearInterval(this.timer);
  //   const { currentTime, now, start } = this.state;
  //   this.setState({
  //     currentTime: currentTime + now - start,
  //     start: 0,
  //     now: 0,
  //   });
  // };

  const resetHandler = () => {
    setState({
      currentTime: 0,
      start: 0,
      now: 0,
    });
  };

  // resetHandler = () => {
  //   this.setState({
  //     currentTime: 0,
  //     start: 0,
  //     now: 0,
  //   });
  // };

  const resumeHandler = () => {
    const now = new Date().getTime();
    setState({
      start: now,
      now,
    });
    setTimer(
      setInterval(() => {
        setState((prev) => ({ ...prev, now: new Date().getTime() }));
      }, 100)
    );
  };

  // resumeHandler = () => {
  //   const now = new Date().getTime();
  //   this.setState({
  //     start: now,
  //     now,
  //   });
  //   this.timer = setInterval(() => {
  //     this.setState({ now: new Date().getTime() });
  //   }, 100);
  // };

  // render() {
  const { now, start, currentTime } = state;
  // const { now, start, currentTime } = this.state;

  return (
    <View style={styles.container}>
      <Timer interval={currentTime + (now - start)} style={styles.timer} />
      <ButtonsRow>
        <RoundButton title={'Start'} color={'#50D167'} background={'#1B361F'} onPress={startHandler} />
        <RoundButton title={'Stop'} color={'#E33935'} background={'#3C1715'} onPress={stopHandler} />
        <RoundButton title={'Reset'} color={'#FFFFFF'} background={'#3D3D3D'} onPress={resetHandler} />
        <RoundButton title={'Resume'} color={'#50D167'} background={'#1B361F'} onPress={resumeHandler} />
      </ButtonsRow>
    </View>
  );
}
// }

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#0D0D0D',
    alignItems: 'center',
    paddingTop: 130,
    paddingHorizontal: 20,
  },
  timer: {
    color: '#FFFFFF',
    fontSize: 76,
    fontWeight: '200',
    width: 110,
  },
  button: {
    width: 80,
    height: 80,
    borderRadius: 40,
    justifyContent: 'center',
    alignItems: 'center',
  },
  buttonTitle: {
    fontSize: 18,
  },
  buttonBorder: {
    width: 76,
    height: 76,
    borderRadius: 38,
    borderWidth: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  buttonsRow: {
    flexDirection: 'row',
    alignSelf: 'stretch',
    justifyContent: 'space-between',
    marginTop: 80,
    marginBottom: 30,
  },
  timerContainer: {
    flexDirection: 'row',
  },
});

试一试:

useEffect(() => {    
  clearInterval(timer);  
}, []);

在useEffect中使用return时,该代码仅在组件卸载时触发。