为什么 AsyncStorage 在第一次单击时保存一个空数组,然后仅在第二次单击 react native 时才保存输入的值

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 将任务保存在我的 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>
  );
}

查看代码,它先保存然后更新数组,因此您的存储总是落后一步:

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');

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

你的项目取得成功。