Skip to content

Instantly share code, notes, and snippets.

@kpunith8
Last active July 4, 2021 08:23
Show Gist options
  • Save kpunith8/63fc65ccae5aa22c1b94ea3d46e92b11 to your computer and use it in GitHub Desktop.
Save kpunith8/63fc65ccae5aa22c1b94ea3d46e92b11 to your computer and use it in GitHub Desktop.
React Custom hooks
const storeContext = React.createContext()
const dispatchContext = React.createContext()
export const StroreProvider = ({childre, reducer, initialState = {}}) => {
const [store, dispatch] = React.useReducer(reducer, initialState)
return (
<dispatchContext.Provider value={dispatch}>
<storeContext.Provider value={store}>
{children}
</storeContext.Provider>
</dispatchContext.Provider>
)
}
export function useStore() {
return React.useContext(storeContext)
}
export function useDispatch() {
return React.useContext(dispatchContext)
}
// Usage
import {useStore, useDispatch} from './store'
const UseStoreEx = () => {
const {todos} = useStore()
const dispatch = useDispatch()
return ()
}
// With global store and local storage
export default function makeStore(userReducer, initialState, key) {
const storeContext = React.createContext()
const dispatchContext = React.createContext()
// Global store + local storage
try {
initialState = JSON.parse(localStorage.getItem(key)) || initialState
} catch(e) {
console.error(e.message)
}
const reducer = (state, action) => {
const newState = userReducer(state, action)
localStorage.setItem(key, JSON.stringify(newState))
return newState
}
const StroreProvider = ({childre}) => {
const [store, dispatch] = React.useReducer(reducer, initialState)
return (
<dispatchContext.Provider value={dispatch}>
<storeContext.Provider value={store}>
{children}
</storeContext.Provider>
</dispatchContext.Provider>
)
}
function useStore() {
return React.useContext(storeContext)
}
function useDispatch() {
return React.useContext(dispatchContext)
}
return [StoreProvider, useStore, useDispatch]
}
// Todo's Store
const todoReducer = (state, action) => ({})
const [TodosProvider, useTodos, useTodoDispatch] = makeStore(todoReducer, [])
export {TodosProvider, useTodos, useTodoDispatch}
// Layout's Store
const layoutReducer = (state, action) => ({})
const [LayoutsProvider, useLayout, useLayoutDispatch] = makeStore(layoutReducer, {})
export {LayoutsProvider, useLayout, useLayoutDispatch}
// Usage
const App = () => {
return (
<TodosProvider>
<LayoutsProvider>
<Todos />
</LayoutsProvider>
</TodosProvider>
)
}
// Todos
const Todos = () => {
const {todos} = useTodos()
const todosDispatch = useTodoDispatch()
return (
{todos.map(todo => ())}
)
}
// Menu
import useClickOutside from './use-click-outside'
const Menu = () => {
const menuRef = React.useRef()
const {isMenuOpen} = useLayout()
const dispatch = useLayoutDispatch()
useClickOutside(menuRef, () => dispatch({type: 'toggleMenu', isOpen: false}))
return (
<div ref={menuRef} className="menu" onClick={onMenuClick}>
</div>
)
}
function useClickOutside(elemRef, callback) {
const callbackRef = React.useRef()
callbackRef.current = callback
React.useEffect(() => {
const handleClickOutside = e => {
if(elemRef?.current?.contains(e.target) && callbackRef.current) {
callbackRef.current(e)
}
}
document.addEventListener('click', handleClickOutside, true)
return () => {
document.removeEventListener('click', handleClickOutside, true)
}
}, [callbackRef, elemRef])
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment