0

我尝试使用 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>
  );
}
4

1 回答 1

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

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

在您的项目上取得成功。

于 2021-04-26T21:31:42.050 回答