With a bunch of state management library out there. All you need is something you already have. React Context with the help of hooks can be your go-to for smaller project.
Making custom hooks is one of React concept you will need to know.
Lately I have been using a custom hook to handle my global state for ease of use.
Custom Hook
Here is an example.
Always name your custom hook starting with use, so react will treat it as a hook.
useCtxDark.jsx
import { useState, createContext, useContext, useMemo } from 'react'
const darkContext = createContext(null)
export const DarkProvider = ({ children }) => {
const [dark, setDark] = useState(false)
const darkValue = useMemo(() => [dark, setDark], [dark])
return
<darkContext.Provider value={darkValue}>
{children}
</darkContext.Provider>
}
export default function useCtxDark() {
return useContext(darkContext)
}
In our custom hook we define our createContext(), and a state either useState or useReducer where we store data. Then we store that data to memoize it in useMemo to reduce re-renders.
Notice that we have 2 exports. A named export which is gonna be our Provider that wraps our app and a default export which is our hook that is used to get and set our data.
Now we setup it up by wrapping our app with our Context Provider
App.jsx
import { DarkProvider } from '@/hooks/useCtxDark'
export default function App() {
return (
// Wrapper
<DarkProvider>
<Nav />
<Pages />
</DarkProvider>
)
}
Then we us it like a hook and have access to the global state where ever we call this hook.
DarkToggle.jsx
import useCtxDark from '@/hooks/useCtxNav'
const Nav = () => {
const [dark, setDark] = useCtxDark()
return <input type='checkbox' onChange={() => setDark(!dark)} />
}
Here is an example using useReducer
import { useReducer, useContext, createContext, useMemo } from 'react'
const globalContext = createContext(null)
const initialState = {
todo: []
}
const reducer = (state, action) => {
switch (action.type) {
case "ADD":
return { todo: [...state.todo, action.payload] };
case "DELETE":
const filltered = state.todos.filter((x) => x.id !== action.payload)
return {
...state,
todos: [...filltered],
}
default:
return state;
}
}
export const GlobalProvider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, initialState)
const stateValue = useMemo(() => [state, dispatch], [state])
return
<globalContext.Provider value={stateValue}>
{children}
</globalContext.Provider>
}
export default function useCtxDark() {
return useContext(globalContext)
}
And you can make multiples of these together when you need more!
Providers.jsx
import { DarkProvider } from '@/hooks/useCtxDark'
import { NavProvider } from '@/hooks/useCtxNav'
const Providers = ({children}) => {
return(
<DarkProvider>
<NavProvider>
{children}
</NavProvider>
</DarkProvider>
)
}
Multi-Context
Another version, where you make a separate context for your state and dispatch.
useStore.jsx
import { useState, createContext, useContext, useMemo } from 'react'
const storeContext = createContext(null)
const dispatchContext = createContext(null)
export const StoreProvider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, initialState)
return
<dispatchContext.Provider value={dispatch}>
<storeContext.Provider value={state}>
{children}
</storeContext.Provider>
</darkContext.Provider>
}
export function useCtxStore() {
return useContext(storeContext)
}
export function useCtxDispatch() {
return useContext(dispatchContext)
}
Then import just the hook for store
import {useCtxStore, useCtxDispatch} from './useStore'
const Component = () => {
const {todos} = useCtxStore()
const dispatch = useCtxDispatch()
const clickHandler = (id) => {
dispatch({type: '', payload: id})
}
return(
<ul>
{todos.map((item) =>
<li key={item.id} onClick={() => clickHandler(item.id)}>
{item.name}
</li>
)}
</ul>
)
}
Here is a live example with all the above hooks
If your planning to do get some asynchronous data. I do recommend that you use a library for data fetching like React Query or SWR for better UX and Dev Exp.
A perfect pair to React Context for a light weight State Management for both Global and Synchronous State!
Top comments (0)