Skip to content

Instantly share code, notes, and snippets.

@saddacracker
Last active February 15, 2023 17:30
Show Gist options
  • Save saddacracker/20496ae854ce322e9fa6373217ec66e4 to your computer and use it in GitHub Desktop.
Save saddacracker/20496ae854ce322e9fa6373217ec66e4 to your computer and use it in GitHub Desktop.
useContext, useReducer example with Local Storage
// 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