I am updating a list (kind of like a todo list) and trying to persist it to AsyncStorage but the latest item added to array is always missing. Why?
Here is the offending function (shortened for clarification):
// At beginning of component
let [itemsArray, updateItemsArray] = useState([])
const addItem = async (item) => {
const currentItem = {
id: uuid(), // <-- temporary way of getting key for now
name: item.name
}
// Use spread operator to update stateful array for screen listing
// The listing on the screen updates perfectly with the 'new item' in place at the bottom
of a list
updateJobsArray(prevItems => [...prevItems, currentJob])
// Now, stringify the items array in preparation for saving to AsyncStorage
updateItemsArray(prevItems => [...prevItems, currentItem])
try {
const jsonValue = JSON.stringify(itemsArray)
await AsyncStorage.setItem('items', jsonValue)
} catch (e) {
Alert.alert('Error', 'Something went horribly, irrevocably... wrong')
}
}
When I console.log AsyncStorage.getItem('items'), the last item added is always missing from the resultant list of items. The items list is always missing the last added item. I think that the problem lies in the way the spread operator updates the stateful 'itemsArray'. It's like as if the state update is async and the write to AsyncStorage happens before the update is finished, but I can't find out why, please help...
CodePudding user response:
I reproduce issue with working example, please test code at https://snack.expo.dev/@emmbyiringiro/c65dbb
import * as React from 'react';
import { Text, View, StyleSheet,Button,AsyncStorage,Alert,ScrollView } from 'react-native';
import Constants from 'expo-constants';
import faker from 'faker'
// You can import from local files
import AssetExample from './components/AssetExample';
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';
export default function App() {
let [itemsArray, updateItemsArray] = React.useState([])
let [savedUsers, updateSavedUsers] = React.useState([])
let [asyncOps,updateAsyncOps] = React.useState({saveStatus:"undetermined",retrieveStatus:"undetermined"})
const save = async ()=>{
const newUser ={
id:faker.datatype.uuid()
,
name: faker.name.findName(), // Rowan Nikolaus
email: faker.internet.email(),// [email protected],
phone:faker.phone.phoneNumber(),
}
const tempUsers = [...itemsArray,newUser]
const serializeValues = JSON.stringify(itemsArray)
try {
updateAsyncOps({...asyncOps,saveStatus:"pending"})
await AsyncStorage.setItem('users', serializeValues)
await retrieve()
updateItemsArray(tempUsers)
updateAsyncOps({...asyncOps,saveStatus:"succeeded"})
} catch (e) {
updateAsyncOps({...asyncOps,saveStatus:"failed"})
Alert.alert('Error', 'Something went horribly, irrevocably... wrong')
}
}
const retrieve = async () => {
try {
updateAsyncOps({...asyncOps,retrieveStatus:"pending"})
const value = await AsyncStorage.getItem('users');
if (value !== null) {
// We have data!!
console.log(value);
const deSerializeValue = JSON.parse(value)
updateSavedUsers( deSerializeValue)
updateAsyncOps({...asyncOps,retrieveStatus:"suceeded"})
}
} catch (error) {
// Error retrieving data
Alert.alert('Error', 'Something went horribly, irrevocably... wrong')
updateAsyncOps({...asyncOps,retrieveStatus:"failed"})
}
};
return (
<ScrollView style={styles.container}>
<Card>
<View>
{ savedUsers.map(user=>{
return (
<View style={{paddingVertical:5}} key={user.id}>
<Text> { user.name} </Text>
<Text> { user.email} </Text>
<Text> { user.phone} </Text>
</View>
)
})}
</View>
<View style={{padding:10}}>
<Button onPress={save} title ='Add User ' disabled={asyncOps.saveStatus === 'pending'}/>
<View style={{paddingVertical:10}}>
<Button onPress={retrieve} title ='Retrieve Users ' disabled={asyncOps.retrieveStatus === 'pending'}/>
</View>
</View>
</Card>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
});