I'm quite new to coding and I'm currently practicing the useReducer()
hook in React to manage some state in a simple todo app.
I'm having trouble when trying to implement the TOGGLE_TODO action. I've done it before using arrays, but as I'll likely be working with a lot of objects, I'm trying to figure out why I can't get this right. I'd say I'm learning by failing, but all I'm learning is how to switch the computer off and walk away!
Each time I toggle, I'm passing the state with the spread operator, I've tried it throughout all of the item, I've logged out the key
and action.payload
to make sure I'm getting a match (it works when I do a simple alert with matching).
I'm aware that the toggle isn't a toggle yet, I was just trying to simply get complete
to be true
.
I've tried a multitude of things to return state, I've added return to the beginning of the statement, and I"ve encountered some weird bugs along the way. As mentioned, this is quite simple state for now, but it will be more complex in another project I'm working on, so useState get's quite messy.
Any help on what I'm doing wrong here would be highly appreciated.
const initialAppState = {
isOpen: true,
todos: {}
};
export const ACTIONS = {
TOGGLE_MODAL: "toggle-modal",
ADD_TODO: "add-todo",
TOGGLE_TODO: "toggle-todo"
};
const reducer = (state, action) => {
// switch statement for actions
switch (action.type) {
case ACTIONS.TOGGLE_MODAL:
return { ...state, isOpen: !state.isOpen };
case ACTIONS.ADD_TODO:
return {
...state,
todos: {
...state.todos,
// Object is created with Unix code as the key
[Date.now()]: {
todo: action.payload.todo,
complete: false
}
}
};
case ACTIONS.TOGGLE_TODO:
// Comparing the key and the action payload. If they match, it should set complete to 'true'. This will be updated to a toggle when working.
Object.keys(state.todos).map((key) => {
if (key === action.payload) {
return {
...state,
todos: { ...state.todos, [key]: { complete: true } }
};
}
return state;
});
default:
throw new Error("Nope. not working");
}
};
In the render, I pass the key
as an id
so it can get returned with the payload.
Here is the dispatch
function from the component...
const Todo = ({ id, value, dispatch }) => {
return (
<div className="todo">
<h1>{`Todo: ${value.todo}`}</h1>
<p>Done? {`${value.complete}`}</p>
<button
onClick={() =>
dispatch({
type: ACTIONS.TOGGLE_TODO,
payload: id
})
}
>
Mark as Done
</button>
</div>
);
};
and the render is using Object.entries
which all works just fine. There were times when I'd get an error, or the initial todo
would disappear, so I knew that state wasn't being updated correctly.
Here is the code on CodeSandbox too. I'll update here if I get it working, but I've been stuck here a couple of days. :-(