最近创建的对象未保存
Most recently created object not being saved
我正在制作一个成绩计算器应用程序,我正在尝试使用 AsyncStorage 在本地保存我的数据,这样如果应用程序被刷新,它应该能够加载我之前拥有的关于每个主题的信息。我已经创建了我的保存、加载、useEffect 函数;但是,它会保存除最近创建的对象之外的所有对象。这意味着如果我创建 4 个“主题”,它只会节省 3 个;如果我创建 5 个“主题”,它会节省 4 个;如果我创建 1 个“主题”,它会保存 0 个。
起初,我以为是因为我在添加课程之前进行了保存,但我不相信是这样,因为我尝试在 addCourse() 中调用 save() 并且没有任何变化。我是 JavaScript 的新手,非常感谢您的帮助!这是我的代码:
Main.js
import React, { useState, useEffect } from 'react';
import {StyleSheet, View, Text, FlatList, TouchableOpacity, Modal,
TouchableWithoutFeedback, Keyboard } from 'react-native';
import AsyncStorage from '@react-native-community/async-storage';
import { globalStyles } from '../styles/global';
import Card from '../shared/card';
import { MaterialIcons } from '@expo/vector-icons';
import ReviewForm from '../screens/reviewForm';
export default function Home({navigation}){
const [modalOpen, setModalOpen] = useState(false);
const [courses, setCourses] = useState([])
const addCourse = (course) => {
course.key = Math.random().toString();
setCourses((currentCourses) => {
return[course, ...currentCourses]
});
setModalOpen(false);
console.log('add course')
console.log(courses)
}
const STORAGE_KEY = '@save_course'
const save = async() => {
try{
console.log('running save');
await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(courses))
} catch(err){
alert('error')
console.log(err)
}
// console.log(courses)
};
const load = async() => {
try{
console.log('running load');
const jsonSubject = await AsyncStorage.getItem(STORAGE_KEY)
console.log('load await');
if(jsonSubject != null){
console.log('entered load if');
setCourses(JSON.parse(jsonSubject));
}
} catch(err){
alert('error')
console.log(err)
}
};
useEffect(() => {
console.log('useEffect');
load()
}, [])
return(
<View style={globalStyles.container}>
<Modal visible={modalOpen} animationType='slide'>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={styles.modalContent}>
<MaterialIcons
name='arrow-back'
style = {{ ...styles.modalToggle, ...styles.modalClose }}
size={24}
onPress={() => setModalOpen(false)}
/>
<ReviewForm addCourse={addCourse} save={save}/>
</View>
</TouchableWithoutFeedback>
</Modal>
<FlatList
style={{flex: 1, backgroundColor: '#efefef'}}
data={courses}
renderItem={({ item }) => (
<TouchableOpacity onPress={() => navigation.navigate('CourseDetails', item)}>
<Card>
<Text style={globalStyles.titleText}>{ item.course }</Text>
</Card>
</TouchableOpacity>
)}
/>
<MaterialIcons
name='add'
size={28}
style={styles.modalToggle}
onPress={() => setModalOpen(true)}
/>
</View>
)
}
const styles = StyleSheet.create({
modalToggle:{
backgroundColor: 'maroon',
color: '#efefef',
width: 75,
height: 75,
borderRadius: 50,
elevation: 6,
padding: 23,
alignSelf: 'flex-end',
position: 'absolute',
right: 15,
bottom: 15,
},
fabIcon: {
fontSize: 28,
color: '#efefef'
},
modalClose:{
left: 10,
marginTop: 30,
marginBottom: 10,
marginRight: 15,
backgroundColor: '#fff',
color: '#242424',
width: 30,
height: 20,
borderRadius: 0,
elevation: 0,
padding: 0,
alignSelf: 'flex-start',
position: 'relative',
},
modalContent:{
flex: 1,
}
});
reviewForm.js
import React from 'react';
import { StyleSheet, TextInput, View, Text } from 'react-native';
import { globalStyles } from '../styles/global.js';
import { Formik } from 'formik';
import * as yup from 'yup';
import FlatButton from '../shared/button';
const courseSchema = yup.object({
course: yup.string()
.required()
.min(3),
prof: yup.string()
.min(2),
// gpa: yup.string()
// .test('is-num-1-10', 'GPA must be a number between 1 - 10', (val) => {
// return parseInt(val) < 11 && parseInt(val) > 0;
// })
})
export default function ReviewForm({ addCourse, save }) {
return(
<View style={globalStyles.container}>
<Formik
initialValues={{ course: '', prof: '' }}
validationSchema={courseSchema}
onSubmit={(values, actions ) => {
actions.resetForm();
console.log('resetForm');
addCourse(values);
console.log('values');
console.log(values);
save();
console.log('save');
}}
>
{(props) => (
<View>
<TextInput
style={globalStyles.input}
placeholder='Course Name'
onChangeText={props.handleChange('course')}
value={props.values.course}
onBlur={props.handleBlur('course')}
/>
<Text style={globalStyles.errorText}>{ props.touched.course && props.errors.course }</Text>
<TextInput
style={globalStyles.input}
placeholder='Professor'
onChangeText={props.handleChange('prof')}
value={props.values.prof}
onBlur={props.handleBlur('prof')}
/>
<Text style={globalStyles.errorText}>{ props.touched.prof && props.errors.prof }</Text>
<FlatButton text='save' onPress={props.handleSubmit} />
</View>
)}
</Formik>
</View>
)
}
尝试在您的 FlatList 组件上添加 extraData 属性。
例如:
extraData={this.state}
所以当状态改变时,平面列表将被刷新并显示新项目
所以我想通了为什么我的代码从未添加最新课程的问题。原因是因为setState是异步的,而save()是同步的,所以虽然我在setState之后调用了save(),但是之前已经在执行了,所以最后一个没有保存。我解决这个问题的方法是复制我的数组,并将课程添加到新数组,这样我在调用 save() 之前手动添加我的课程,所以我知道我所有的课程都被保存了。这是新代码...
const addCourse = (course) => {
course.key = Math.random().toString();
newCourses = [course, ...courses]
setCourses(newCourses);
save(newCourses);
setModalOpen(false);
}
希望这对将来遇到与我相同问题的人有所帮助!
我正在制作一个成绩计算器应用程序,我正在尝试使用 AsyncStorage 在本地保存我的数据,这样如果应用程序被刷新,它应该能够加载我之前拥有的关于每个主题的信息。我已经创建了我的保存、加载、useEffect 函数;但是,它会保存除最近创建的对象之外的所有对象。这意味着如果我创建 4 个“主题”,它只会节省 3 个;如果我创建 5 个“主题”,它会节省 4 个;如果我创建 1 个“主题”,它会保存 0 个。
起初,我以为是因为我在添加课程之前进行了保存,但我不相信是这样,因为我尝试在 addCourse() 中调用 save() 并且没有任何变化。我是 JavaScript 的新手,非常感谢您的帮助!这是我的代码:
Main.js
import React, { useState, useEffect } from 'react';
import {StyleSheet, View, Text, FlatList, TouchableOpacity, Modal,
TouchableWithoutFeedback, Keyboard } from 'react-native';
import AsyncStorage from '@react-native-community/async-storage';
import { globalStyles } from '../styles/global';
import Card from '../shared/card';
import { MaterialIcons } from '@expo/vector-icons';
import ReviewForm from '../screens/reviewForm';
export default function Home({navigation}){
const [modalOpen, setModalOpen] = useState(false);
const [courses, setCourses] = useState([])
const addCourse = (course) => {
course.key = Math.random().toString();
setCourses((currentCourses) => {
return[course, ...currentCourses]
});
setModalOpen(false);
console.log('add course')
console.log(courses)
}
const STORAGE_KEY = '@save_course'
const save = async() => {
try{
console.log('running save');
await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(courses))
} catch(err){
alert('error')
console.log(err)
}
// console.log(courses)
};
const load = async() => {
try{
console.log('running load');
const jsonSubject = await AsyncStorage.getItem(STORAGE_KEY)
console.log('load await');
if(jsonSubject != null){
console.log('entered load if');
setCourses(JSON.parse(jsonSubject));
}
} catch(err){
alert('error')
console.log(err)
}
};
useEffect(() => {
console.log('useEffect');
load()
}, [])
return(
<View style={globalStyles.container}>
<Modal visible={modalOpen} animationType='slide'>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={styles.modalContent}>
<MaterialIcons
name='arrow-back'
style = {{ ...styles.modalToggle, ...styles.modalClose }}
size={24}
onPress={() => setModalOpen(false)}
/>
<ReviewForm addCourse={addCourse} save={save}/>
</View>
</TouchableWithoutFeedback>
</Modal>
<FlatList
style={{flex: 1, backgroundColor: '#efefef'}}
data={courses}
renderItem={({ item }) => (
<TouchableOpacity onPress={() => navigation.navigate('CourseDetails', item)}>
<Card>
<Text style={globalStyles.titleText}>{ item.course }</Text>
</Card>
</TouchableOpacity>
)}
/>
<MaterialIcons
name='add'
size={28}
style={styles.modalToggle}
onPress={() => setModalOpen(true)}
/>
</View>
)
}
const styles = StyleSheet.create({
modalToggle:{
backgroundColor: 'maroon',
color: '#efefef',
width: 75,
height: 75,
borderRadius: 50,
elevation: 6,
padding: 23,
alignSelf: 'flex-end',
position: 'absolute',
right: 15,
bottom: 15,
},
fabIcon: {
fontSize: 28,
color: '#efefef'
},
modalClose:{
left: 10,
marginTop: 30,
marginBottom: 10,
marginRight: 15,
backgroundColor: '#fff',
color: '#242424',
width: 30,
height: 20,
borderRadius: 0,
elevation: 0,
padding: 0,
alignSelf: 'flex-start',
position: 'relative',
},
modalContent:{
flex: 1,
}
});
reviewForm.js
import React from 'react';
import { StyleSheet, TextInput, View, Text } from 'react-native';
import { globalStyles } from '../styles/global.js';
import { Formik } from 'formik';
import * as yup from 'yup';
import FlatButton from '../shared/button';
const courseSchema = yup.object({
course: yup.string()
.required()
.min(3),
prof: yup.string()
.min(2),
// gpa: yup.string()
// .test('is-num-1-10', 'GPA must be a number between 1 - 10', (val) => {
// return parseInt(val) < 11 && parseInt(val) > 0;
// })
})
export default function ReviewForm({ addCourse, save }) {
return(
<View style={globalStyles.container}>
<Formik
initialValues={{ course: '', prof: '' }}
validationSchema={courseSchema}
onSubmit={(values, actions ) => {
actions.resetForm();
console.log('resetForm');
addCourse(values);
console.log('values');
console.log(values);
save();
console.log('save');
}}
>
{(props) => (
<View>
<TextInput
style={globalStyles.input}
placeholder='Course Name'
onChangeText={props.handleChange('course')}
value={props.values.course}
onBlur={props.handleBlur('course')}
/>
<Text style={globalStyles.errorText}>{ props.touched.course && props.errors.course }</Text>
<TextInput
style={globalStyles.input}
placeholder='Professor'
onChangeText={props.handleChange('prof')}
value={props.values.prof}
onBlur={props.handleBlur('prof')}
/>
<Text style={globalStyles.errorText}>{ props.touched.prof && props.errors.prof }</Text>
<FlatButton text='save' onPress={props.handleSubmit} />
</View>
)}
</Formik>
</View>
)
}
尝试在您的 FlatList 组件上添加 extraData 属性。
例如:
extraData={this.state}
所以当状态改变时,平面列表将被刷新并显示新项目
所以我想通了为什么我的代码从未添加最新课程的问题。原因是因为setState是异步的,而save()是同步的,所以虽然我在setState之后调用了save(),但是之前已经在执行了,所以最后一个没有保存。我解决这个问题的方法是复制我的数组,并将课程添加到新数组,这样我在调用 save() 之前手动添加我的课程,所以我知道我所有的课程都被保存了。这是新代码...
const addCourse = (course) => {
course.key = Math.random().toString();
newCourses = [course, ...courses]
setCourses(newCourses);
save(newCourses);
setModalOpen(false);
}
希望这对将来遇到与我相同问题的人有所帮助!