Skip to content

Instantly share code, notes, and snippets.

@sebringj
Last active May 8, 2021 00:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sebringj/0b305a605a538dea30766001e1d839f8 to your computer and use it in GitHub Desktop.
Save sebringj/0b305a605a538dea30766001e1d839f8 to your computer and use it in GitHub Desktop.
This is a really simple way to do global state in react
import firebase from 'firebase'
import { SimpleStore } from './SimpleStore'
export type AuthState = {
loggedIn: boolean,
user?: firebase.User
}
const authStore = new SimpleStore<AuthState>('auth', {
loggedIn: false,
})
export default authStore
import useAuth from './useAuth'
const SomeControl = () => {
const [authState, setAuthState] = useAuth()
return (
<>
<div>logged in?: {authState.loggedIn}</div>
<a onClick={() => setAuthState({ loggedIn: !authState.loggedIn })}>{authState.loggedIn ? 'Log Out' : 'Log In'}</a>
</>
)
}
import EventEmitter from 'eventemitter3'
export enum SimpleStoreEvents {
change = 'change'
}
export class SimpleStore<T> {
constructor(storeName: string, state: T) {
this._state = state
this._storeName = storeName
this._hydrate()
}
private _hydrate() {
if (typeof window === 'undefined') return
this._storeKey = `simple_store_${this._storeName}`
try {
const json = localStorage[this._storeKey] as string
json && this.setState(JSON.parse(json) as T)
} catch (err) {
console.error(err)
}
}
private _storeKey: string
private _storeName: string
private _ee = new EventEmitter()
private _state: T
public get state() {
return this._state
}
public setState(state: Partial<T>) {
this._state = { ...this._state, ...state }
localStorage[this._storeKey] = JSON.stringify(this._state)
this._ee.emit(SimpleStoreEvents.change)
}
public onChange(fn: () => void | (() => Promise<void>)) {
this._ee.on(SimpleStoreEvents.change, fn)
}
public offChange(fn: () => void | (() => Promise<void>)) {
this._ee.off(SimpleStoreEvents.change, fn)
}
}
import authStore from './authStore'
import useGlobalState from './useGlobalState'
export default () => useGlobalState(authStore)
import { useState, useEffect } from 'react'
import { SimpleStore } from '../stores/SimpleStore'
function useGlobalState<T>(store: SimpleStore<T>): [T, (state: Partial<T>) => void] {
const [state, setState] = useState<T>(store.state)
useEffect(() => {
function onChange() {
setState(store.state)
}
store.onChange(onChange)
return () => {
store.offChange(onChange)
}
}, [])
return [state, store.setState.bind(store)]
}
export default useGlobalState
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment