Last active
February 15, 2023 17:30
-
-
Save saddacracker/20496ae854ce322e9fa6373217ec66e4 to your computer and use it in GitHub Desktop.
useContext, useReducer example with Local Storage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Persist Application State locally with useReducer & useContext. | |
// AppReducer.js | |
export const initialState = { | |
number: 0, | |
} | |
export const AppReducer = (state, action) => { | |
switch (action.type) { | |
case 'REPLACE_STATE': | |
return action.payload | |
case 'SET_NUMBER': { | |
return { | |
...state, | |
number: action.payload, | |
} | |
} | |
default: | |
return state | |
} | |
} | |
// AppContext.js | |
import { | |
createContext, | |
useContext, | |
useMemo, | |
useReducer, | |
useEffect, | |
} from 'react' | |
import { AppReducer, initialState } from '../reducers/AppReducer' | |
const AppContext = createContext() | |
export const AppProvider = ({ children }) => { | |
const [state, dispatch] = useReducer(AppReducer, initialState) | |
useEffect(() => { | |
if (!!localStorage['myapp:app']) { | |
// checking if there already is a myapp:app in localstorage | |
// if yes, update the current state with the stored one | |
dispatch({ | |
type: 'REPLACE_STATE', | |
payload: JSON.parse(localStorage.getItem('myapp:app')), | |
}) | |
} | |
}, []) | |
useEffect(() => { | |
if (state !== initialState) { | |
// create and/or set a new localstorage variable called "myapp:app" | |
localStorage.setItem('myapp:app', JSON.stringify(state)) | |
} | |
}, [state]) | |
const contextValue = useMemo(() => { | |
return { state, dispatch } | |
}, [state, dispatch]) | |
return ( | |
<AppContext.Provider value={contextValue}>{children}</AppContext.Provider> | |
) | |
} | |
export const useAppContext = () => { | |
const context = useContext(AppContext) | |
if (context === undefined || context === null) { | |
throw new Error(`useAppContext must be called within AppProvider`) | |
} | |
return context | |
} | |
// _app.js | |
import { AppProvider } from '../contexts/AppContext' | |
import 'tailwindcss/tailwind.css' | |
export default function MyApp({ | |
Component, | |
pageProps: { session, ...pageProps }, | |
}) { | |
return ( | |
<AppProvider> | |
<Component {...pageProps} /> | |
</AppProvider> | |
) | |
} | |
// MyComponent.jsx | |
import React, { useEffect } from 'react' | |
import { useAppContext } from '../contexts/AppContext' | |
const MyComponent = () => { | |
const { state, dispatch } = useAppContext() | |
useEffect(() => { | |
dispatch({ type: 'SET_NUMBER', payload: 69 }) | |
}, []) | |
return <div>{state.number}</div> | |
} | |
export default MyComponent |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment