I am trying to use ASyncStorage inside of the useState hook to load data from storage if present. I am rendering the todos inside a map function but before that I am checking whether todos is undefined or []. The logic should be returning [] to useState if the data is not present but it is giving undefined!
Here is the code:
export default function App() {
const [todo, setTodo] = useState('');
const [todos, setTodos] = useState(async () => {
try {
const value = await AsyncStorage.getItem('@MySuperStore:key');
// We have data!!
return value ? JSON.parse(value) : [];
} catch (error) {
// Error retrieving data
console.log(error);
}
});
const addItem = (newTodo) => {
if (newTodo.length === 0) {
Alert.alert(
'Enter a String',
'You have entered a string with 0 characters',
[{ text: 'Okay', style: 'default' }]
);
} else {
console.log(newTodo);
let newTodos = [newTodo, ...todos];
setTodo('');
_storeData(newTodos).then(_retrieveData());
// setTodos(newTodos);
}
};
const deleteTodo = (idx) => {
setTodos(todos.filter((todo, id) => id !== idx));
};
const _storeData = async (value) => {
try {
await AsyncStorage.setItem('@MySuperStore:key', JSON.stringify(value));
} catch (error) {
// Error saving data
console.log(error);
}
};
const _retrieveData = async () => {
try {
const value = await AsyncStorage.getItem('@MySuperStore:key');
if (value !== null) {
// We have data!!
setTodos(JSON.parse(value));
console.log(value);
}
} catch (error) {
// Error retrieving data
console.log(error);
}
};
return (
<TouchableWithoutFeedback
onPress={() => {
Keyboard.dismiss();
}}
>
<View style={styles.outerContainer}>
<Text style={styles.header}>TODO</Text>
<View style={styles.container}>
<TextInput
placeholder='new todo'
style={styles.input}
value={todo}
onChangeText={(text) => {
setTodo(text);
}}
></TextInput>
<Button title='Add' onPress={() => addItem(todo)}></Button>
</View>
<ScrollView style={styles.scrollView}>
{todos === [] || todos === undefined ? (
<View>
<Text>Add a todo!</Text>
</View>
) : (
todos.map((todo, idx) => (
<View style={styles.todo} key={idx}>
<Text style={styles.todoText}>{todo}</Text>
<View style={styles.delete}>
<Button
color='red'
title='Delete'
onPress={() => deleteTodo(idx)}
></Button>
</View>
</View>
))
)}
</ScrollView>
</View>
</TouchableWithoutFeedback>
);
}
CodePudding user response:
I'm not sure why the default state of todos
would use an async function, that doesn't make sense to me. Instead I would do const [todos, setTodos] = useState([]);
and leverage useEffect
hook something similar to this:
useEffect(() => {
(async () => {
try {
const value = await AsyncStorage.getItem('@MySuperStore:key');
// We have data!!
setTodos(value ? JSON.parse(value) : [])
} catch (error) {
// Error retrieving data
console.log(error);
}
})();
},[]);