Home > Enterprise >  How can I save the values in the context to local storage?
How can I save the values in the context to local storage?

Time:08-29

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 {}

       }

     }
  }

}
  • Related