何が嬉しいの?
Windowをまたがった情報共有ができる。
ただし多用すると状態管理が散乱するので避けた方良い。
実装
import { useEffect, useState, useRef } from 'react'; const useCrossWindowState = <T>( stateKey: string, defaultValue: T, ): [state: T, setState: (state: T) => void] => { const [state, setState] = useState<T>(defaultValue); const isNewSession = useRef(true); useEffect(() => { if (isNewSession.current) { const currentState = localStorage.getItem(stateKey); if (currentState) { setState(JSON.parse(currentState)); } else { setState(defaultValue); } isNewSession.current = false; return; } try { localStorage.setItem(stateKey, JSON.stringify(state)); } catch (error) {} }, [state, stateKey, defaultValue]); useEffect(() => { const onReceieveMessage = (e: StorageEvent) => { const { key, newValue } = e; if (key === stateKey) { setState(JSON.parse(newValue ?? '')); } }; window.addEventListener('storage', onReceieveMessage); return () => window.removeEventListener('storage', onReceieveMessage); }, [stateKey, setState]); return [state, setState]; }; export default useCrossWindowState;
使い方
useStateと同じ感じ。
const [volume, setVolume] = useCrossWindowState<number>('audioVolume', 15);
参考
react-cross-windows-state - CodeSandbox
さいごに
TypeScript対応をするときの型を探すのが地味に手間。
でもanyに逃げない*1。
*1:今回だとStorageEvent