Edit - added minimally reproducible example: https://snack.expo.dev/@hdorra/code
I hope everyone can access the snack. So if you add a task, you can see it show up in the log. Click on the circle, it shows as true (meaning it is clicked). Save and refresh and everything is stored (the task) but the checkbox is not. I stripped the code to make it as bare minimum as possible but it shows the problem.
It has been days of me on this error. I am relatively new to stackoverflow so my apologies if my question isn't clear or I am not asking it in the correct format. I am trying to create a to do app in react native that is using async storage. I created a toggle button that saves the toggle to a state. This button is located in a component:
const [checkBoxState, setCheckBoxState] = React.useState(false);
const toggleComplete = () => {
setCheckBoxState(!checkBoxState)
handleEdit();
console.log(checkBoxState)
}
When the user checks on it - seems to be showing up correctly as marked true and false in the console. Then, this is passed to an edit handler to update the array, again console shows it is the correct state:
const handleEdit = () => {
props.editHandler(props.todoKey, text, checkBoxState);
console.log(text2, checkBoxState)
};
Then it shows that it saved correctly:
const [todos, setTodos] = React.useState([]);
const handleEdit = (todoKey, text, newStatus) => {
const newTodos = [...todos];
const index = newTodos.findIndex(todos => todos.key === todoKey);
newTodos[index] = Object.assign(newTodos[index], {title: text, status: newStatus});
setTodos(newTodos);
console.log(todos, newStatus)
};
The async function to save to the device and load are as follows: To save:
const saveTodoToUserDevice = async (todos) => {
try {
const stringifyTodos = JSON.stringify(todos);
await AsyncStorage.setItem('todos', stringifyTodos);
} catch (error) {
console.log(error);
}
};
To load from the device:
const getTodosFromUserDevice = async () => {
try {
const todos = await AsyncStorage.getItem('todos');
if (todos != null) {
setTodos(JSON.parse(todos));
console.log("loaded successfully");
}
} catch (error) {
console.log(error);
}
};
So here is the issue - I get the console log that says it is saved correctly and loaded. BUT, when I refresh, the checkbox state is not saved at all, just the title text (so it is saving but the checkbox would always be false (the initial state set). If I clicked on true, it would show as true and then when I refresh, it goes back to false.
I have spent days and days on this and can't figure it out. Any direction would be helpful Thank you!
CodePudding user response:
I have gone trough your code and found some errors you are making in different places. In Task.js
you can do without that checkBoxState
. For that pass the status
to Task
as props
while rendering it in FlatList
, like so:
<Task
key={item.key}
todoKey={item.key}
title={item.title}
status={item.status}
editHandler={handleEdit}
pressHandler={handleDelete}
/>
Then as below change the button to toggle the status
, so you use what's coming from the props
and create a function called toggleStatus
and pass it to onPress
:
<TouchableOpacity onPress={toggleStatus}>
<View
style={[
styles.circle,
!props.status ? styles.completeCircle : styles.incompleteCircle,
]}
></View>
</TouchableOpacity>
The code for toggleStatus
:
const toggleStatus = () => {
props.editHandler(props.todoKey, props.title, !props.status);
};
And handleEdit
would be simplified to:
const handleEdit = () => {
props.editHandler(props.todoKey, text2, props.status);
setEdit(false);
console.log(props.status);
};
Lastly in TasksMain.js
so you don't replace what's in the storage with that initial array given to useState
, make sure saveTodoToUserDevice
runs after getTodosFromUserDevice
. For that add the below state in TasksMain.js
and change slightly the two functions as follow:
const [loading, setLoading] = React.useState(true);
const saveTodoToUserDevice = async (todos) => {
if (loading) return;
try {
const stringifyTodos = JSON.stringify(todos);
await AsyncStorage.setItem("todos", stringifyTodos);
} catch (error) {
console.log(error);
}
};
const getTodosFromUserDevice = async () => {
try {
const todos = await AsyncStorage.getItem("todos");
if (todos != null) {
setTodos(JSON.parse(todos));
console.log("loaded successfully");
}
} catch (error) {
console.log(error);
} finally {
setLoading(false);
}
};