我正在构建一个秒表,其中有一个计时器,并且计时器应该运行,将时间保存到异步存储中,以便能够检索它并从应用程序被终止然后重新启动时计时器到达的位置恢复。所以问题是时间正在被保存,但是当我尝试检索它时,该值是 0 而不是保存的值。我需要您的帮助才能检索到正确的值以及我是否正确保存了它。这种节省方式是我从构建以前的应用程序中获得的,该应用程序工作完美,但在我现在正在构建的应用程序中却不是这样
这是我的代码:
import React, { useState, useRef, useEffect, useCallback } from 'react';
import { View, Text, TouchableOpacity, StyleSheet, Image, Modal, Platform } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
export default function StopwatchScreen() {
const [menuVisible, setMenuVisible] = useState(false);
const [backgroundColor, setBackgroundColor] = useState('#11167F');
const [headerBackgroundColor, setHeaderBackgroundColor] = useState('#0a1055');
const [isRunning, setIsRunning] = useState(false);
const [time, setTime] = useState(0);
const [retrievedTime, setRetrievedTime] = useState(0);
const intervalRef = useRef(null);
const handleLapButtonPress = useCallback(() => {
if(isRunning) {
} else {
setTime(0);
setRetrievedTime(0);
saveAsync('time', 0);
console.log("cleared time: ", time);
console.log("cleared retrieved time: ", retrievedTime);
}
}, [isRunning]);
const handleStartButtonPress = async () => {
setIsRunning(!isRunning);
saveAsync('isRunning', !isRunning);
saveAsync('time', time);
};
useEffect(() => {
if (isRunning) {
console.log("it is running");
intervalRef.current = setInterval(() => {
if(retrievedTime > 0) {
console.log("retrieved > 0");
setTime(previousTime => retrievedTime + previousTime + 100);
} else {
console.log("retrieved not > 0");
setTime(previousTime => previousTime + 100);
}
}, 100);
} else {
clearInterval(intervalRef.current);
console.log("it stopped");
}
return () => clearInterval(intervalRef.current);
}, [isRunning]);
useEffect(() => {
saveAsync('time', time);
}, [time]);
const toggleMenu = () => {
setMenuVisible(!menuVisible);
}
const displayTime = () => {
const milliseconds = parseInt((time%1000)/10);
const centiseconds = Math.floor(milliseconds/10);
const seconds = parseInt((time/1000)%60);
const minutes = parseInt((time/(1000*60))%60)
const hours = parseInt((time/(1000*60*60))%24);
return {
hours: pad(hours),
minutesSeconds: pad(minutes % 60) + ':' + pad(seconds % 60),
centiseconds: centiseconds,
};
};
const pad = (number) => {
return number < 10 ? '0' + number : number;
};
const retrieveAsync = async (key) => {
try {
const jsonValue = await AsyncStorage.getItem(key);
if (jsonValue !== null) {
const parsedValue = JSON.parse(jsonValue);
console.log("parsedValue: ", parsedValue);
if(key === 'time') {
setRetrievedTime(parsedValue);
console.log("retrieve "+key+" inside: ", retrievedTime);
}
}
} catch (e) {
// error reading value
console.log('error: ', e);
}
};
const saveAsync = async (key, value) => {
AsyncStorage.setItem(key, JSON.stringify(value));
console.log(key+" value saved: ", value);
};
useEffect(() => {
console.log("Real retrieved time: ", retrievedTime);
setTime(previousTime => previousTime + retrievedTime);
}, [retrievedTime]);
useEffect(() => {
retrieveAsync('time');
console.log("useEffect retrieved time: ", retrievedTime);
}, []);
return (
<View style={[styles.container, Platform.OS === 'android' && styles.androidPadding]}>
<View style={[styles.header, {backgroundColor: headerBackgroundColor}]}>
<Text style={[styles.title, styles.textFont]}>Futuristic Stopwatch</Text>
<TouchableOpacity onPress={toggleMenu}>
<Image source={require('../assets/images/three_dots.png')} style={styles.dotsIcon} />
</TouchableOpacity>
</View>
<Modal
transparent={false}
animationType="slide"
visible={menuVisible}
onRequestClose={() => setMenuVisible(false)}
>
<View style={styles.modalContainer}>
Modal
</View>
</Modal>
<View style={[styles.contentContainer, {backgroundColor: backgroundColor}]}>
<View style={styles.rowHud}>
<Text style={[styles.hoursTimerOverlay, styles.textFont]}>{`${displayTime(time).hours}`}</Text>
<Text style={[styles.timerOverlay, styles.textFont]}>{`${displayTime(time).minutesSeconds}`}</Text>
<Text style={[styles.centisecondsTimerOverlay, styles.textFont]}>{`${displayTime(time).centiseconds}`}</Text>
</View>
<View style={styles.controls}>
<TouchableOpacity onPress={handleStartButtonPress} style={[styles.controlButtonBorder, { backgroundColor: isRunning ? "#340e0d" : "#0a2a12" }]}>
<View style={styles.controlButton}>
<Text style={{ color: isRunning ? "#ea4c49" : "#37d05c" }}>{isRunning ? 'Stop' : 'Start'}</Text>
</View>
</TouchableOpacity>
<TouchableOpacity onPress={handleLapButtonPress} style={[styles.controlButtonBorder, { backgroundColor: isRunning ? "#333333" : "#1c1c1e" }]}>
<View style={styles.controlButton}>
<Text style={{ color: isRunning ? "#fff" : "#9d9ca2" }}>{isRunning ? 'Lap' : 'Reset'}</Text>
</View>
</TouchableOpacity>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
padding: 0,
},
androidPadding: {
paddingTop: Platform.OS === 'android' ? 25 : 0,
},
header: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 0,
paddingTop: 18,
paddingBottom: 15,
paddingLeft: 10,
paddingRight: 10,
},
title: {
fontSize: 18,
//fontWeight: 'bold',
color: 'white',
},
dotsIcon: {
width: 20,
height: 20,
resizeMode: 'contain',
},
modalContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(0, 0, 0, 0.5)',
},
textFont: {
fontFamily: 'Orbitron Black',
},
modalContent: {
backgroundColor: '#fff',
padding: 20,
borderRadius: 10,
elevation: 5,
},
closeButton: {
position: 'absolute',
top: 10,
right: 10,
},
sectionTitle: {
flexDirection: 'row',
alignItems: 'center',
marginTop: 10,
},
sectionTitleText: {
fontFamily: 'Orbitron Black',
},
radioBox: {
marginTop: 20,
alignItems: 'flex-start',
width: 300,
},
radioOptions: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 10,
},
contentContainer: {
flex: 1,
},
rowHud: {
flex: 0.6,
flexDirection: 'row',
marginBottom: 0,
marginTop: 10
},
timerOverlay: {
position: 'absolute',
top: '50%', // Adjust as needed
left: '50%', // Adjust as needed
transform: [{ translateX: -90 }, { translateY: -30 }],
fontSize: 50,
color: 'white',
},
hoursTimerOverlay: {
position: 'absolute',
top: '35%', // Adjust as needed
left: '50%', // Adjust as needed
transform: [{ translateX: -30 }, { translateY: -30 }],
fontSize: 35,
color: 'white',
},
centisecondsTimerOverlay: {
position: 'absolute',
top: '71%', // Adjust as needed
left: '50%', // Adjust as needed
transform: [{ translateX: -15 }, { translateY: -35 }],
fontSize: 35,
color: 'white',
},
controls: {
flexDirection: 'row',
justifyContent: 'space-between',
paddingLeft: 20,
paddingRight: 20,
},
controlButtonBorder: {
justifyContent: "center",
alignItems: "center",
width: 70,
height: 70,
borderRadius: 70,
},
controlButton: {
justifyContent: "center",
alignItems: "center",
width: 65,
height: 65,
borderRadius: 65,
borderColor: "#000",
borderWidth: 1
},
image: {
width: '100%',
height: '100%',
paddingLeft: 10,
paddingRight: 10
}
});
当您从 AsyncStorage 检索时间时,使用该值设置时间状态。
调整秒表运行时时间的添加方式。添加前一个时间和检索到的时间可能会造成不准确。
// ... (other imports and styles)
export default function StopwatchScreen() {
// ... (existing code remains the same)
useEffect(() => {
retrieveAsync('time');
}, []);
useEffect(() => {
if (isRunning) {
intervalRef.current = setInterval(() => {
setTime(previousTime => previousTime + 100);
}, 100);
} else {
clearInterval(intervalRef.current);
}
return () => clearInterval(intervalRef.current);
}, [isRunning]);
const retrieveAsync = async (key) => {
try {
const jsonValue = await AsyncStorage.getItem(key);
if (jsonValue !== null) {
const parsedValue = JSON.parse(jsonValue);
if (key === 'time') {
setTime(parsedValue); // Set the retrieved time here
setRetrievedTime(parsedValue);
}
}
} catch (e) {
console.log('error: ', e);
}
};
const handleStartButtonPress = () => {
setIsRunning(!isRunning);
saveAsync('isRunning', !isRunning);
};
const handleLapButtonPress = () => {
if (isRunning) {
// Do something for lap when running
} else {
setTime(0);
saveAsync('time', 0); // Reset time when stopped
}
};
// ... (rest of the existing code remains the same)
}