Skip to content

Instantly share code, notes, and snippets.

@wiledal
Last active May 17, 2019 00:05
Show Gist options
  • Save wiledal/0a1e816abd051d3d9564d716cc153eb7 to your computer and use it in GitHub Desktop.
Save wiledal/0a1e816abd051d3d9564d716cc153eb7 to your computer and use it in GitHub Desktop.
A basic global-state hook pattern for React
import React from 'react'
import { useGlobalState } from '../hooks/useGlobalState.js'
export default function App () {
// The first time we call useGlobalState, we can set the default state, ignored after that.
const [ globalState, setGlobalState ] = useGlobalState({
count: 0,
theme: 'light'
})
const style = {
background: globalState.theme === 'light' ? '#fff' : '#000',
color: globalState.theme === 'light' ? '#000' : '#fff',
}
return (
<div style={style}>
<Content />
</div>
)
}
function Content (props) {
const [ globalState, setGlobalState ] = useGlobalState()
function handleChangeThemeClick() {
// setGlobalState MERGES the object into the old object, to only update the key-value pairs supplied.
// Notice how the "count" value would normally be removed
setGlobalState({
theme: globalState.theme === 'light' ? 'dark' : 'light'
})
}
function handleCountClick() {
setGlobalState({
count: globalState.count + 1
})
}
return (
<div>
<h2>
The theme is {globalState.theme}
</h2>
<button onClick={handleChangeThemeClick}>
Change theme
</button>
<button onClick={handleCountClick}>
I have been clicked {globalState.count} time(s)
</button>
</div>
)
}
import React, { useState, useEffect } from 'react'
// This is the object that keeps the state
let state = null
let initiated = false
// The array of state setter-methods
const setters = []
// The method that updates ALL the setters
function setState (obj) {
let newState = Object.assign({}, state, obj)
state = newState
setters.forEach(setter => setter(newState))
}
export function useGlobalState (initialState) {
if (!initiated && initialState) {
state = initialState
}
initiated = true
// Create a new state
const [ s, ss ] = useState(state)
// Add the setter of the new state to array of setters
if (!setters.includes(ss)) setters.push(ss)
useEffect(() => {
// When hook is destroyed, remove unused setter from array of setters
return () => {
setters.splice(setters.indexOf(ss), 1)
}
}, [])
// Return global state object, and the global state setter method
return [ state, setState ]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment