アドレスバーの有無で追従系のレイアウトずれる問題をuseSyncExternalStoreで解決する
useSyncExternalStoreとは名前の通り、hooksじゃない値の変動に対して再レンダリングさせる事ができる。
アドレスバーの有無でinnerHeightが変動するのでそのタイミングでコンポーネントの再レンダリングをする事で
レイアウトのズレに対処可能。
code:tsx
const subscribe = useCallback((update: () => void) => {
window.addEventListener('resize', update)
return () => window.removeEventListener('resize', update)
}, [])
const viewportHeight = useSyncExternalStore(
subscribe,
() => window.innerHeight,
() => 0
)
return (
<ModalBody
style={{
// Modal全体の高さが100vhを超えるとヘッダー全体がスクロールされて表示が崩れるので超えない様にする。
// viewportHeight - ModalHeaderの高さ64px - 上下の余白
height: viewportHeight - 64 - 48
}}
/>
)
bottom: 0みたいに再計算されたinnerHeightが不要な場合は
code:tsx
const _viewportHeight = useSyncExternalStore( /* 略 */)
って感じで使わない変数をつくりつつ、あえてメモ化しないことで対応可能。
あるいは
code:tsx
const StickyFooter = () => {
const forceUpdate = useReducer(() => window.innerHeight, 0)
useEffect(() => {
window.addEventListener('resize', forceUpdate)
return () => window.removeEventListener('resize', forceUpdate)
}, [])
}
こういう方法で再計算させる事も可能。