Last active
May 17, 2019 00:05
-
-
Save wiledal/0a1e816abd051d3d9564d716cc153eb7 to your computer and use it in GitHub Desktop.
A basic global-state hook pattern for React
This file contains hidden or 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
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> | |
) | |
} |
This file contains hidden or 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
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