viewport에 따라 컴포넌트의 길이가 변할 때 취해야 할 작업이 종종 존재한다. 이전 과거를 떠오르면 달력 컴포넌트, Tabs 컴포넌트를 만들 때가 이에 해당한다.
조금 더 자세한 예시를 들자면 다음과 같다.
위는 Tabs 컴포넌트이다. Panel1부터 Panel10까지 모두 viewport 내에서 확인할 수 있다. 하지만 가로의 길이를 줄이다 보면 Panel10부터 화면에서 사라지게 될 것이다. 때문에 가려지는 것을 방지하기 위해 추가 작업이 필요하다.
Tabs의 컴포넌트같은 경우엔 화살표를 추가하여 사용자가 화살표를 클릭하여 보이지 않는 Panel를 찾는 것이 해결방법이 될 것이다.
이와 같은 기능을 구현하기 위해선 가로(혹은 세로)의 사이즈가 변하는 것을 감지할 수 있어야 한다.
어떻게 감지할 수 있는지? 어떤 방법이 있는지? 알아본다.
1. resize 이벤트 사용하기
가장 먼저 떠오르는 것은 `resize`이벤트이다.
function App() {
const ref = useRef<HTMLDivElement>(null);
const [width, setWidth] = useState<number | null>(null);
const updateWidth = () => {
if (!ref.current) return;
setWidth(ref.current.offsetWidth);
};
useEffect(() => {
if (!ref.current) return;
window.addEventListener('resize', updateWidth);
return () => window.removeEventListener('resize', updateWidth);
}, []);
return (
<div
ref={ref}
style={{
width: '100%',
height: '50px',
background: 'rgba(230, 230, 230)',
}}
>
<span>박스의 너비는 {width}입니다.</span>
</div>
);
}
window의 사이즈가 변할 때마다 updateWidth함수를 호출한다. updateWidth함수에서는 ref로 등록한 div박스의 가로 사이즈를 확인하고 width상태를 업데이트하고 있다.
2. ResizeObserver API 사용하기
두 번째 방법은 `ResizeObserver API`를 사용하는 것이다.
function App() {
const ref = useRef<HTMLDivElement>(null);
const [width, setWidth] = useState<number | null>(null);
useEffect(() => {
if (!ref.current) return;
const resizeObserver = new ResizeObserver(([box]) => {
// 첫번째 매개변수로 관찰대상을 배열로 받는다.
// 여기에서는 관찰대상이 하나이기 때문에 간단히 구조분해할당으로 가져왔다.
setWidth(box.contentRect.width);
});
resizeObserver.observe(ref.current); // 관찰 대상을 등록한다.
return () => {
if (!ref.current) return;
resizeObserver.unobserve(ref.current); // 관찰 대상을 해제한다.
};
}, []);
return (
<div
ref={ref}
style={{
width: '100%',
height: '50px',
background: 'rgba(230, 230, 230)',
}}
>
<span>박스의 너비는 {width}입니다.</span>
</div>
);
}
ref를 사용하는 것은 마찬가지이다. ref로 등록한 어떠한 요소의 `resize`를 관찰하겠다는 것이다.
ResizeObserver 생성자를 호출하고 콜백함수에 관찰하고자 하는 요소의 사이즈가 변할 때마다 어떤 동작을 해야 하는지를 작성하면 된다.
ReiszeObserver API에 대한 자세한 설명은 MDN 문서에서 확인할 수 있다.
https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver