为什么 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');
这样您将始终保存任务列表中的任何更新,并防止在首次渲染组件时将其保存为空。
你的项目取得成功。
我尝试使用 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');
这样您将始终保存任务列表中的任何更新,并防止在首次渲染组件时将其保存为空。
你的项目取得成功。