[英]clearInterval() not working in React Native - trying to convert from class to functional components - Timer
尝试在本机反应中制作秒表我有 class 组件的工作代码,但是在尝试使用功能组件时clearInterval()
function 不起作用
修改前来自 ReactNativeAcademy/Stopwatch 的源代码https://github.com/ReactNativeAcademy/Stopwatch/blob/master/App.js
I need just a basic timer without laps with only start / resume / stop / reset buttons snack url for my code: https://snack.expo.io/@mansouriala/nervous-mixed-nuts in order to test it in class based您可以在功能之一下找到基于 function 注释的每个 class 组件。
我不知道,但可能的一种解决方案是将 setInterval 包装在 useEffect 中,然后创建一个新的 state 变量,在启动时将其切换为 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时,代码仅在组件卸载时触发。
不要在 state 中存储间隔 id 之类的东西,因为每次更新都会重新渲染。 如果您功能正常,请使用setInterval
实现useRef()
,如果基于 class ,请使用this.interval
。
另一个问题是在 ref 的功能组件中调用clearInterval()
,而不是.current
这是我刚刚调试的一个片段:
const spinnerCount = useRef(0)
const interval = useRef(null)
useEffect(() => {
if (withProgress && inProgress && notification == '') {
interval.current = setInterval(() => {
if (spinnerCount.current >= 40) {
clearInterval(interval.current)
spinnerCount.current = 0
setNotification('Something happened... Please try again.')
} else {
spinnerCount.current = spinnerCount.current + 1
}
}, 1000)
}
if (notification !== '' && inProgress === false) {
const delay = notification.length > 100 ? 6000 : 3000
setTimeout(() => {
clearInterval(interval.current)
spinnerCount.current = 0
setNotification('');
}, delay);
}
}, [inProgress])
里面有一些额外的东西,基本上这是一个消失的通知组件,它还具有一个进度微调器。 在这种情况下,如果组件正在显示微调器,但从未触发成功/错误通知,则微调器将在 40 秒后自动退出。 因此间隔/微调器计数
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.