I've created functionality for users to add their favorite recipes to a list, they can then view a list of their saved recipes, however I'm trying to get the array of recipes to persist to local storage so the data is not lost on refresh.
I've saved the data and tried updating the state to what's in the local storage but the data does not persist
const [myRecipeState, dispatchMyRecipes] = useReducer(myRecipesReducer, {items: []});
const addItemHandler = (item) => {
dispatchMyRecipes({val:'ADD', item: item});
}
const removeItemHandler = (id) => {
dispatchMyRecipes({val:'REMOVE', id: id});
}
const myRecipesReducer = (state, action) => {
if (action.val === 'ADD') {
let updatedItems;
let updatedItem;
const existingItemIndex = state.items.findIndex(item => item.id === action.item.id)
const existingItem = state.items[existingItemIndex];
const localRecipes = JSON.parse(localStorage.getItem('myRecipes'));
if (existingItem) {
updatedItems = [...state.items];
updatedItem = existingItem;
updatedItems[existingItemIndex] = updatedItem;
console.log('item already exists');
localStorage.setItem('myRecipes', JSON.stringify(updatedItems));
}else {
updatedItems = state.items.concat(action.item);
console.log('item added for the first time');
localStorage.setItem('myRecipes', JSON.stringify(updatedItems));
}
return {items: localRecipes || updatedItems}
}
if (action.val === 'REMOVE') {
let updatedItems;
const localRecipes = JSON.parse(localStorage.getItem('myRecipes'));
updatedItems = [...state.items].filter(item => item.id !== action.id);
localStorage.setItem('myRecipes', JSON.stringify(updatedItems));
return {items: localRecipes || updatedItemsupdatedItems}
}
return {items: state.items}
}
First thing you are doing wrong is that you are always starting with an empty array. Change your initial state so that you pick what's within the localStorage if there is and if not use an empty array:
const initialData = localStorage.getItem("myRecipes")
? JSON.parse(localStorage.getItem("myRecipes"))
: [];
const [myRecipeState, dispatchMyRecipes] = useReducer(myRecipesReducer, { items: initialData });
Then you should slightly change myRecipesReducer as some things you have there are not correct, like this localRecipes || updatedItems will always pick localRecipes.
const myRecipesReducer = (state, action) => {
if (action.val === "ADD") {
const existingItemIndex = state.items.findIndex((item) => item.id === action.item.id);
let updatedItems;
if (existingItemIndex !== -1) {
updatedItems = [...state.items];
updatedItems[existingItemIndex] = action.item;
} else {
updatedItems = state.items.concat(action.item);
}
localStorage.setItem("myRecipes", JSON.stringify(updatedItems));
return { items: updatedItems };
}
if (action.val === "REMOVE") {
const updatedItems = state.items.filter((item) => item.id !== action.id);
localStorage.setItem("myRecipes", JSON.stringify(updatedItems));
return { items: updatedItems };
}
return { items: state.items };
};
The issue seems to be that the keys you're using when setting and getting your state differ.
You could add a const localstorageKey = 'myRecipes'; at the top of your file. Then, reuse this variable when calling both setItem and getItem. This will save you some refactoring pain in the future, and avoid bugs like this one.