Closed3
useSyncExternalStoreとResizeObserverを使って要素のリサイズ発生時に幅と高さを取得するhooksを作る
ResizeObserver
- ブラウザAPI
- 要素のサイズ変化を監視し、変化するたびに渡したコールバックを実行する
- 特定の要素のサイズ変更を検知して、その要素が変化した後のパラメータで何か処理を行いたいと時などに使う
例
div要素のサイズ変更を検知して、divの幅をコンソールに出力するプログラム
...
const [width, setWidth] = useState(0);
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const observer = new ResizeObserver((entries) => {
entries.forEach((entry)=>setWidth(entry.contentRect.width));
});
if(ref.current){
observer.observe(ref.current);
}
return () => observer.disconnect();
},[])
// 下記のdivのサイズが変化した時、幅がセットされ再描画が起きるため、widthがコンソールに表示される。
console.log(width)
return <div ref={ref} />
useSyncExternalStore
- 外部のデータストアへサブスクライブすることで値を読み取ることができるhooks
- 可変のブラウザAPIへサブスクライブすることで、値を読み取るなどに使う
例
ブラウザのネットワークの接続状態が変化するたびに状態を更新して画面を再描画するプログラム
import { useSyncExternalStore } from 'react';
function callback = () => navigator.online;
function subscribe(callback) {
window.addEventListener('online', callback);
window.addEventListener('offline', callback);
// サブスクライブ関数の戻り値はイベントに対するリスナーを解除する関数を返す必要がある
return () => {
window.removeEventListener('online', callback);
window.removeEventListener('offline', callback);
};
}
const isOnline = useSyncExternalStore(subscribe, callback);
return <div>{isOnline ? "Online" : "Offline"}</div>
useSyncExternalStoreとResizeObserverを使って要素のリサイズ発生時に幅と高さを取得するhooks
export const useResizeObserver = <T extends HTMLElement>() => {
const ref = useRef<T>(null);
const subscribe = useCallback((onStoreChange: () => void) => {
const observer = new ResizeObserver((entries) => {
// 監視対象の要素がリサイズした際、useSyncExternalStoreフックから渡される、
// 画面の再描画を行う関数を実行する。
entries.forEach(() => onStoreChange());
});
if (ref.current) {
observer.observe(ref.current);
}
return () => observer.disconnect();
}, []);
const height = useSyncExternalStore(
subscribe,
() => ref.current?.clientHeight || 0
);
const width = useSyncExternalStore(
subscribe,
() => ref.current?.clientWidth || 0
);
return { ref, width, height };
};
SSRを使うアプリの場合
useSyncExternalStoreの第3引数に、サーバーサイドレンダリング時の初期値を返す処理を設定する
このスクラップは2024/04/13にクローズされました