[英]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.