react-use has a cool useLocalStorage
module that allows you to do what it sounds like it allows you to do - read values into state from the localStorage. You can also find the generally straight forward source for it here.
This lib mostly handles the serialization but I wanted to add a watcher to the storage key as well. I generally don't recommend binding your state to localStorage like this but I needed to and it let me quickly implement some cool features for CloudSynth Inbox.
I went on to extend that library for our use cases, but I wanted to write out a simplified version. I'm really enjoying the encapsulation provided by hooks in react in typescript. Its very simple to write a decent utility like useLocalStorage
.
function useLocalStorageLite<T>(key: string) {
// pull the initial value from local storage if it is already set
const [state, setState] = useState<T | null>(() => {
const exValue = localStorage.getItem(key)
if (exValue) {
return JSON.parse(exValue) as T
}
return null
})
// save the new value when it changes
useEffect(() => {
localStorage.setItem(key, JSON.stringify(state))
}, [state])
// memoize a storage watcher callback back because everything in hooks should be memoized
const storageWatcher = useCallback(
(e: StorageEvent) => {
if (e.newValue) {
// update ours if we
setState((currState) => {
const newDat = JSON.parse(e.newValue || "null")
return newDat == state ? newDat : currState
})
}
},
[state]
)
// install the watcher
useEffect(() => {
window.addEventListener("storage", storageWatcher)
// stop listening on remove
return () => {
window.removeEventListener("storage", storageWatcher)
}
}, [state])
return { state, setState }
}
Now, we're missing a few things like error catching and a correct equality check but this is pretty neat and clean. I returned to frontend development recently and its nice to see these hooks cleaning things up quite a bit. It's very easy (as you should) to extend the existing react-use
implementation with a few lines too. It's also nice to see the emergence of headless UI libs enabled by hooks.
There are definitely going to be some annoyances like a ton of useEffects and useCallbacks and you might need useWhyDidYouUpdate at some point but the complexity seems inherent to the problem.
So overall, hooks are nice.