首页 > 解决方案 > clearInterval() 在 React Native 中不起作用 - 尝试从类转换为功能组件 - 计时器

问题描述

尝试在本机反应中制作秒表我有带有类组件的工作代码但是在尝试使用功能组件时该clearInterval()功能不起作用

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

我只需要一个没有圈数的基本计时器,我的代码只有开始/恢复/停止/重置按钮小吃网址:https ://snack.expo.io/@mansouriala/nervous-mixed-nuts 以便在基于类的测试组件,您可以在功能性功能下找到每个基于类的功能。

我不知道,但可能的一种解决方案是将 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',
  },
});

标签: javascriptreact-nativetimerreact-hookssetinterval

解决方案


试试看:

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

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


推荐阅读