【问题标题】:Why does AsyncStorage save an empty array with the first click and then save the entered value only with the second button click in react native为什么 AsyncStorage 在第一次单击时保存一个空数组,然后仅在反应本机中单击第二个按钮时才保存输入的值
【发布时间】:2021-04-26 20:53:00
【问题描述】:

我尝试使用 AsyncStorage 将任务保存在我的 ToDo 应用中,以便在应用重启后可以检索它们。

到目前为止,我已经设法保存了这些任务。但是,空数组总是在第一次运行时保存。如果我想创建一个新任务,它只会在我第二次单击按钮时保存。如果整个事情异步运行,则合乎逻辑。我只是想不通我的错在哪里。我很乐意收到帮助和提示。

这里可以看到创建第一个任务时的空数组: Reactotron Empty Array

在这里您可以看到在我创建第二个任务后保存的第一个值: Reactotron AsyncStorage after second click

第一部分:

if (__DEV__) {
  import('./ReactotronConfig').then(() => console.log('Reactotron Configured'));
}
import Reactotron, { asyncStorage } from 'reactotron-react-native';
import React, { useState, useEffect } from 'react';
import {
  Keyboard,
  KeyboardAvoidingView,
  Platform,
  StyleSheet,
  Text,
  TextInput,
  TouchableOpacity,
  View,
  ScrollView,
  Image,
  SafeAreaView,
} from 'react-native';

import AsyncStorage from '@react-native-async-storage/async-storage';
import Task from './components/Task';

export default function App() {
  const [task, setTask] = useState();
  const [taskItems, setTaskItems] = useState([]);

  const getData = async () => {
    try {
      const jsonValue = await AsyncStorage.getItem('TASKS');
      const jsonValue2 = JSON.parse(jsonValue);
      if (jsonValue2 !== null) {
        setTaskItems(jsonValue2);
      }
    } catch (e) {
      alert(e);
    }
  };

  const storeData = async () => {
    await AsyncStorage.clear();
    try {
      const jsonValue = await AsyncStorage.setItem(
        'TASKS',
        JSON.stringify(taskItems)
      );
      return jsonValue;
      Reactotron.log(jsonValue);
    } catch (e) {
      alert(e);
    }
  };

  useEffect(() => {
    getData();
  }, []);

  const handleAddTask = () => {
    storeData();
    Keyboard.dismiss();
    setTaskItems([...taskItems, task]);
    setTask(null);
  };

  const completeTask = (index) => {
    let itemsCopy = [...taskItems];
    itemsCopy.splice(index, 1);
    setTaskItems(itemsCopy);
  };

  const bearyDustLogo = require('./assets/bearydust-logo-bear-with-text.png');

第二部分:

return (
    <SafeAreaView style={styles.container}>
      <ScrollView style={styles.scrollView}>
        {/* Aufgaben für heute */}

        <View style={styles.tasksWrapper}>
          <View style={styles.headerWrapper}>
            <Text style={styles.sectionTitle}>StandUp Aufgaben</Text>
            <Image style={styles.tinyLogo} source={bearyDustLogo}></Image>
          </View>
          <View style={styles.items}>
            {/* Aufgabenbereich */}
            {taskItems.map((item, index) => {
              return (
                <TouchableOpacity
                  key={index}
                  onPress={() => completeTask(index)}
                >
                  <Task text={item} />
                </TouchableOpacity>
              );
            })}
          </View>
        </View>
      </ScrollView>

      {/* Aufgabe erstellen */}

      <KeyboardAvoidingView
        behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
        style={styles.writeTaskWrapper}
      >
        <TextInput
          style={styles.input}
          placeholder={'Ey! Lass was machen'}
          value={task}
          onChangeText={(text) => setTask(text)}
        />
        <TouchableOpacity
          onPress={() => {
            handleAddTask();
          }}
        >
          <View style={styles.addWrapper}>
            <Text style={styles.addText}>+</Text>
          </View>
        </TouchableOpacity>
      </KeyboardAvoidingView>
    </SafeAreaView>
  );
}

【问题讨论】:

    标签: reactjs react-native asyncstorage react-native-state


    【解决方案1】:

    查看代码,它首先是保存,然后是更新数组,所以你的存储总是落后一步:

    const handleAddTask = () => {
        storeData(); // here you are handling the save
        Keyboard.dismiss();
        setTaskItems([...taskItems, task]); // but you update the values only here
        setTask(null);
      };
    

    为了让您的代码保持简单,我建议您在每次更新 taskItems 时保存,但请记住,您不需要在第一次从存储中加载时进行更新,所以这样的事情应该可以工作:

    export default function App() {
      const [task, setTask] = useState();
      const [taskItems, setTaskItems] = useState([]);
      const [loading, setLoading] = useState(true);
    
      const getData = async () => {
        try {
          const jsonValue = await AsyncStorage.getItem('TASKS');
          const jsonValue2 = JSON.parse(jsonValue);
          if (jsonValue2 !== null) {
            setTaskItems(jsonValue2);
          }
        } catch (e) {
          alert(e);
        } finally {
          setLoading(false)
        }
      };
    
      const storeData = async () => {
        // commenting this line as you don't need to clean the storage each time you write something on it, as you'll just override the existing key 'TASKS'
        // await AsyncStorage.clear();
        
        // here you validate if the data was loaded already before starting watching for changes on the list
        if (!loading) {
          try {
            const jsonValue = await AsyncStorage.setItem(
              'TASKS',
              JSON.stringify(taskItems)
            );
            return jsonValue;
            Reactotron.log(jsonValue);
          } catch (e) {
            alert(e);
          }
        }
      }
    
      useEffect(() => {
        getData();
      }, []);
    
      useEffect(() => {
        storeData()
      }, [taskItems])
    
      const handleAddTask = () => {
        // won't need this line anymore as now everything you update your list it will be saved.
        // storeData();
        Keyboard.dismiss();
        setTaskItems([...taskItems, task]);
        setTask(null);
      };
    
      const completeTask = (index) => {
        let itemsCopy = [...taskItems];
        itemsCopy.splice(index, 1);
        // this will trigger a save as well
        setTaskItems(itemsCopy);
      };
    
      const bearyDustLogo = require('./assets/bearydust-logo-bear-with-text.png');
    

    这样,您将始终保存任务列表中的任何更新,并防止在首次渲染组件时将其保存为空。

    您的项目取得成功。

    【讨论】:

    • 我爱你,伙计:D 你救了我的大脑免于爆炸。我不得不将你的 if 语句保存在异步函数中的 useEffect Hook 中,然后在 useEffect 中调用它。否则我有一个错误,等待只能在异步函数中使用。现在,它会将每个条目保存在内存中,并在我将任务标记为已完成时将其删除。你是我的英雄,非常感谢!
    • 很高兴听到它有帮助!我已经使用 async 函数更新了代码,因此任何人都可以将其用作将来的参考。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-03
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多