如何解决React-native应用程序可以进行许多重新渲染,并且功能可以在状态更改时继续运行
我在很多重新发布广告时都遇到了错误。似乎每次状态更新时都会运行compareDate函数。仅当应用程序打开时才必须运行compareDate,以检查自上次登录以来是否为新的一天,以便它可以通过执行addWater(-dailyGoal)重置程序。有谁知道我如何才能让它在打开应用程序后只能运行一次?
import { StatusBar } from 'expo-status-bar';
import React,{ useState } from 'react';
import {
StyleSheet,Text,View,SafeAreaView,Alert,TouchableOpacity,Keyboard,TextInput,} from 'react-native';
import AsyncStorage from '@react-native-community/async-storage';
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
import { faTint,faCog,faTimes } from '@fortawesome/free-solid-svg-icons';
export default function App() {
// set vars
const [waterDrank,setWaterDrank] = useState(0);
const [menuOpen,setmenuOpen] = useState(false);
const [dailyGoal,setDailyGoal] = useState(3700);
const [bottle,setBottle] = useState(250);
const [dailyGoalSettings,onChangeDailyGoalSettings] = useState(
`${dailyGoal}`
);
const [bottleSettings,onChangeBottleSettings] = useState(`${bottle}`);
// Async storage
const storeWater = async (value) => {
try {
await AsyncStorage.setItem('storedWater',value);
} catch (e) {
// saving error
}
};
const getStoredWater = async () => {
try {
const value = await AsyncStorage.getItem('storedWater');
if (value !== null && !isNaN(value)) {
setWaterDrank(parseInt(value));
}
} catch (e) {
// error reading value
}
};
// init stored water data
getStoredWater();
// store settings
const storeSettings = async (daily,bottle) => {
try {
await AsyncStorage.setItem('dailyGoalSetting',daily);
await AsyncStorage.setItem('bottleSetting',bottle);
} catch (e) {
// saving error
}
};
const getStoredSettings = async () => {
try {
const valueDailyGoalSetting = await AsyncStorage.getItem(
'dailyGoalSetting'
);
const valueBottleSetting = await AsyncStorage.getItem(
'bottleSetting'
);
if (
valueDailyGoalSetting !== null &&
!isNaN(valueDailyGoalSetting) &&
valueBottleSetting !== null &&
!isNaN(valueBottleSetting)
) {
setDailyGoal(valueDailyGoalSetting);
setBottle(valueBottleSetting);
}
} catch (e) {
// error reading value
}
};
// init stored settings data
getStoredSettings();
const addWater = (amount) => {
amount = parseInt(amount);
if (!isNaN(amount)) {
if (waterDrank + amount >= dailyGoal) {
setWaterDrank(dailyGoal);
storeWater(`${dailyGoal}`);
} else if (waterDrank + amount <= 0) {
setWaterDrank(0);
storeWater(`0`);
} else {
setWaterDrank(waterDrank + amount);
storeWater(`${waterDrank + amount}`);
}
} else {
setWaterDrank(waterDrank + 0);
storeWater(`${waterDrank + 0}`);
}
};
const compareDate = () => {
const firstDateIsPastDayComparedToSecond = (firstDate,secondDate) =>
firstDate.setHours(0,0) - secondDate.setHours(0,0) <
0;
const currentDate = new Date();
const storedDate = new Date(currentDate);
storedDate.setDate(storedDate.getDate() - 1);
// is the first date in the past
if (firstDateIsPastDayComparedToSecond(storedDate,currentDate)) {
addWater(-dailyGoal);
}
};
compareDate();
const settingsToggle = () => {
setmenuOpen(!menuOpen);
Keyboard.dismiss();
};
const settingsSave = () => {
storeSettings(dailyGoalSettings,bottleSettings);
getStoredSettings();
settingsToggle();
};
return (
<View style={styles.body}>
{/* settings */}
<View
style={[
styles.settingsMenu,{
display: `${menuOpen ? 'block' : 'none'}`,},]}
>
<SafeAreaView onPress={() => Keyboard.dismiss()}>
<TouchableOpacity
style={styles.settingsButton}
onPress={() => settingsToggle()}
>
<FontAwesomeIcon
icon={faTimes}
color={'black'}
size={24}
/>
</TouchableOpacity>
<View style={{ paddingHorizontal: 20 }}>
<Text style={styles.settingsText}>
Daily water goal in ml
</Text>
<TextInput
style={styles.settingsInput}
onChangeText={(text) =>
onChangeDailyGoalSettings(text)
}
value={dailyGoalSettings}
keyboardType={'number-pad'}
/>
<Text style={styles.settingsText}>
Amount of a bottle in ml
</Text>
<TextInput
style={styles.settingsInput}
onChangeText={(text) =>
onChangeBottleSettings(text)
}
value={bottleSettings}
keyboardType={'number-pad'}
/>
<TouchableOpacity
style={styles.settingsSave}
onPress={() => settingsSave()}
>
<Text
style={{
alignSelf: 'center',color: '#fff',fontWeight: 'bold',}}
>
Save
</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
</View>
{/* main content */}
<SafeAreaView style={styles.container}>
<TouchableOpacity
style={styles.settingsButton}
onPress={() => settingsToggle()}
>
<FontAwesomeIcon icon={faCog} color={'white'} size={24} />
</TouchableOpacity>
<View style={styles.wrapper}>
<Text style={styles.textWaterLeft}>
{dailyGoal - waterDrank}
<Text style={styles.textWaterLeftMeasurement}>ml</Text>
</Text>
<Text style={styles.titleText}>
Left to hit your daily goal!
</Text>
</View>
<View style={styles.wrapper}>
<View style={styles.buttonContainer}>
<TouchableOpacity
style={[
styles.button,{
backgroundColor: `${
waterDrank >= dailyGoal
? '#4DAC5F'
: '#0064ED'
}`,]}
onPress={() => addWater(-bottle)}
>
<Text style={styles.buttonText}>
-
<FontAwesomeIcon
icon={faTint}
color={'white'}
/>
</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.button,]}
onPress={() =>
Alert.prompt(
'How much water did you drink?','',[
{
text: 'OK',onPress: (amount) =>
addWater(amount),]
)
}
>
<Text style={styles.buttonText}>+</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.button,]}
onPress={() => addWater(bottle)}
>
<Text style={styles.buttonText}>
+
<FontAwesomeIcon
icon={faTint}
color={'white'}
/>
</Text>
</TouchableOpacity>
</View>
</View>
<StatusBar style="auto" barStyle="dark-content" />
</SafeAreaView>
<View
style={[
styles.indicator,{
height: `${Math.floor(
(100 / dailyGoal) * waterDrank
)}%`,backgroundColor: `${
waterDrank >= dailyGoal ? '#51E66E' : '#1782FF'
}`,]}
></View>
</View>
);
}
const styles = StyleSheet.create({
body: {
flex: 1,backgroundColor: '#152940',container: {
flex: 1,wrapper: {
flex: 1,justifyContent: 'flex-end',alignItems: 'center',indicator: {
position: 'absolute',width: '100%',bottom: 0,zIndex: -1,textWaterLeft: {
fontSize: 77,textWaterLeftMeasurement: {
fontSize: 18,fontWeight: 'normal',marginTop: 200,marginBottom: 10,titleText: {
color: '#fff',fontSize: 18,marginBottom: 30,buttonContainer: {
flexDirection: 'row',justifyContent: 'space-between',flexWrap: 'wrap',button: {
flex: 1,margin: 10,backgroundColor: '#0064ED',borderRadius: 10,buttonText: {
textAlign: 'center',margin: 20,settingsButton: {
height: 40,width: 40,alignSelf: 'flex-end',zIndex: 2,settingsMenu: {
position: 'absolute',height: '100%',backgroundColor: '#fff',zIndex: 200,settingsText: {
marginTop: 30,settingsInput: {
height: 40,borderColor: 'gray',borderWidth: 1,paddingHorizontal: 20,marginTop: 10,settingsSave: {
marginTop: 30,textAlign: 'center',padding: 15,});
解决方法
Ciao,尝试像这样使用useEffect
钩子:
import React,{ useState,useEffect } from 'react';
...
useEffect(() => {
compareDate();
},[])
通过这种方式,compareDate()
仅在组件渲染时触发一次。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。