React Native 如何获取已由扩展运算符更新的有状态数组的最后一个值?

Posted

技术标签:

【中文标题】React Native 如何获取已由扩展运算符更新的有状态数组的最后一个值?【英文标题】:React Native how can I get last value of stateful array which has been updated by a spread operator? 【发布时间】:2022-01-16 06:46:29 【问题描述】:

我正在更新一个列表(有点像待办事项列表)并尝试将其保存到 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 的写入发生在更新完成之前,但我不知道为什么,请帮助...

【问题讨论】:

【参考方案1】:

我重现了工作示例的问题,请在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',
  ,
);



【讨论】:

请不要只发布链接。请使用回答问题的相关代码进行编辑。答案和问题不应依赖外部资源。 @DᴀʀᴛʜVᴀᴅᴇʀ,该链接是开发环境中的解决方案。问题作者可以查看解决方案并测试代码。 答案应该仍然有回答问题的相关部分。可以链接到完整的运行环境,但回答问题的所有相关方面都应该在答案中。这可以防止链接失效。 好的。感谢您的澄清。我在这里添加了解决方案代码。 这是一个非常全面的答案。我实际上编写了一个解决方法,但这段代码看起来更接近我想要的。谢谢@BYIRINGIRO Emmanual

以上是关于React Native 如何获取已由扩展运算符更新的有状态数组的最后一个值?的主要内容,如果未能解决你的问题,请参考以下文章

无法在额外属性扩展上获取属性“ndkVersion”,因为它不存在于... react-native 0.64.0

如何在 React Native 中获取应用商店国家代码

如何在 React-Native 中获取 Android 版本号? (不是 API 级别编号)

无法在 React 中使用扩展运算符更新状态

如何在 react-native 中实现具有透明背景的视频

如何在 React Native 的无状态功能组件中扩展原生组件的 props TypeScript 接口?