Created
July 22, 2020 06:23
-
-
Save donaldpipowitch/af11e77f3caf3212e9abc67cfb2a1597 to your computer and use it in GitHub Desktop.
useLocationState: a glorified location.state for React Router as a hook
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 { useState, useEffect } from 'react'; | |
| import { useLocation, useHistory } from 'react-router-dom'; | |
| import { useSessionStorage } from './use-storage'; // see https://gist.github.com/donaldpipowitch/7310d7b9e4b6d467134c425e8732adc6 | |
| type UseLocationStateOptions<T> = { | |
| defaultValue?: T; | |
| scope?: string; | |
| filter?: (value: T) => boolean; | |
| }; | |
| // this is a glorified `location.state` (needed, because the vanilla | |
| // location state has stricter size limits than `sessionStorage`) | |
| // you can use this as a replacement to `sessionStorage`, if you | |
| // want save "refresh"/"navigate back" behaviour, but if you aren't | |
| // interested in "navigate away" | |
| // (by default the state is _global_, but you can use a scope prefix | |
| // to create individual state) | |
| export function useLocationState<T>(options: UseLocationStateOptions<T> = {}) { | |
| const { defaultValue, scope, filter } = options; | |
| const sessionStorage = useSessionStorage(); | |
| const { key } = useLocation(); | |
| const { replace } = useHistory(); | |
| const scopedKey = key && scope ? `${key}.${scope}` : key; | |
| const [state, setState] = useState(() => { | |
| if (!scopedKey) return defaultValue; | |
| const savedState = sessionStorage.getItem(scopedKey); | |
| if (!savedState) return defaultValue; | |
| return JSON.parse(savedState) as T; | |
| }); | |
| // every time the state changes and we don't filter it a new location.key | |
| // will be generated | |
| useEffect(() => { | |
| if (filter && !filter(state as T)) return; | |
| replace({}); | |
| // eslint-disable-next-line react-hooks/exhaustive-deps | |
| }, [state]); | |
| // every time a new location.key was generated we store the state locally | |
| useEffect(() => { | |
| if (!scopedKey) return; | |
| sessionStorage.setItem(scopedKey, JSON.stringify(state)); | |
| // eslint-disable-next-line react-hooks/exhaustive-deps | |
| }, [scopedKey]); | |
| return [state, setState] as const; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment