React Native 如何获取已由传播运算符更新的有状态数组的最后一个值?
React Native how can I get last value of stateful array which has been updated by a spread operator?
我正在更新一个列表(有点像待办事项列表)并尝试将其保存到 AsyncStorage,但添加到数组的最新项目总是丢失。为什么?
这里是有问题的函数(为清楚起见而缩短):
// 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')
}
}
当我 console.log AsyncStorage.getItem('items') 时,最后添加的项目总是从项目的结果列表中丢失。项目列表总是缺少最后添加的项目。我认为问题在于传播运算符更新有状态 'itemsArray' 的方式。好像状态更新是异步的,写入AsyncStorage发生在更新完成之前,但我找不到原因,请帮助...
我重现了工作示例的问题,请在 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(),// Kassandra.Haley@erich.biz,
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',
},
});
我正在更新一个列表(有点像待办事项列表)并尝试将其保存到 AsyncStorage,但添加到数组的最新项目总是丢失。为什么?
这里是有问题的函数(为清楚起见而缩短):
// 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')
}
}
当我 console.log AsyncStorage.getItem('items') 时,最后添加的项目总是从项目的结果列表中丢失。项目列表总是缺少最后添加的项目。我认为问题在于传播运算符更新有状态 'itemsArray' 的方式。好像状态更新是异步的,写入AsyncStorage发生在更新完成之前,但我找不到原因,请帮助...
我重现了工作示例的问题,请在 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(),// Kassandra.Haley@erich.biz,
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',
},
});