When I add or remove a contact from contact list in the context, I want it to be saved in memory (local storage). The code I wrote for local storage gives an error. How can I do it right? "State.contacts is iterable" error occurs. As soon as I take the code I wrote for Local, everything is fine. Where is the problem?
import React,{ createContext, useReducer } from "react";
import AppReducer from "./AppReducer";
const initialState = {
contacts: [],
};
export const GlobalContext = createContext(initialState);
export const ContextProvider = ({children}) => {
const [state, dispatch] = useReducer(AppReducer, initialState)
// const [state, dispatch] = useReducer(AppReducer, initialState, () => {
// const localData = localStorage.getItem("contacts");
// return localData ? JSON.parse(localData) : []
// })
// useEffect(() => {
// localStorage.setItem("contacts", JSON.stringify(state));
// }, [state])
const ADD_CONTACT = (contacts) => {
dispatch({
type: "ADD_CONTACT",
payload: contacts,
});
};
const REMOVE_CONTACT = (id) => {
dispatch({
type: "REMOVE_CONTACT",
payload: id,
});
};
const UPDATE_CONTACT = (contacts) => {
dispatch({
type: "UPDATE_CONTACT",
payload: contacts,
});
};
return (
<GlobalContext.Provider
value={{
contacts: state.contacts,
ADD_CONTACT,
REMOVE_CONTACT,
UPDATE_CONTACT,
}}
>
{children}
</GlobalContext.Provider>
);
};
const AppReducer = (state, action) =>{
switch(action.type){
case "ADD_CONTACT" :{
return{
...state,
contacts : [...state.contacts,action.payload]
}
}
case "REMOVE_CONTACT":{
return{
...state,
contacts:
state.contacts.filter((contact)=>contact.id !== action.payload)
}
}
case "UPDATE_CONTACT":{
const updatedContact = action.payload;
const updatedContacts = state.contacts.map(contact=>{
if(contact.id === updatedContact.id){
return updatedContact
}
return contact
})
return {
...state,
contacts:updatedContacts
}
}
default:{
return state
}
}
}
export default AppReducer
CodePudding user response:
I think you should rewrite both your reducer and your context provider to fixe your problem.
//Your context provider
// == React
import React, { createContext, useReducer } from 'react'
import { reducers } from './reducers'
const ContactContext = createContext({})
function ContextProvider({ initialState , children }) {
const [ state, dispatch ] = useReducer(
contactReducer,
initialState,
initialContacts => {
const contacts = localStorage.getItem('contacts')
return {
contacts: contacts
}
})
return (
<ContactContext.Provider value={{ state, dispatch }}>
{children}
</ContactContext.Provider>
)
}
And your reducer like so:
export const APP_CONTEXT = {
removeContact: 'REMOVE_CONTACT',
}
export function contactReducer(state, action) {
try {
switch (action.type) {
case APP_CONTEXT.removeContact:
localStorage.setItem('contacts', action.contacts)
return {
...state,
contacts: contacts
}
default: return {}
}
}
}
}