ref를 넘겨주면, width와 height값을 리턴하는 훅으로 만들면 좋을 듯하다.
<aside> 💡 함수가 아닌 훅을 이용하는 이유
커스텀 훅 안에어서는 리액트 훅을 사용할 수 있다. 리액트 훅 중 useEffect는 컴포넌트가 렌더링된 후 실행되는 훅이다. 컴포넌트의 사이즈를 측정하기 위해서는 컴포넌트가 마운트된 후 실행되어야 하기 때문에 커스텀 훅으로 만들어줄 것이다.
</aside>
export default function useComponentSize(ref:React.RefObject<any>) {
const [componentSize,setComponentSize] = useState({
width : 0,
height : 0
})
const handleResize = React.useCallback(()=>{ // 컴포넌트가 렌더링될 때마다 재선언을 할 수 있으니, useCallback으로 메모이제이션을 한다.
if(!ref.current){ // 아직 ref가 돔에 박히지 않았을 때이다. (ref가 박힐 돔이 렌더링되면, ref.current는 해당 돔을 가리키게 된다.
return;
}
const height = ref.current.offsetHeight;
const width = ref.current.offsetWidth;
setComponentSize({
width,height
})
},[ref])
React.useLayoutEffect(()=>{
if(ref.current){
ref.current.addEventListener('load',handleResize);
}else{
handleResize();
}
window.addEventListener('resize',handleResize);
return(()=>{
window.removeEventListener('resize',handleResize);
})
},[ref,handleResize])
return componentSize
}
<aside> 💡 offsetHeight, offsetWidth
: padding + border를 포함한 높이/너비
</aside>
<aside> 💡 React.useCallback
: 리렌더링 간에 함수 정의를 캐싱해준다. 즉, 메모이제이션을 한다.
</aside>
<aside> 💡 React.useLayoutEffect
useEffect는 브라우저가 화면을 그린 후에(layout, paint 후) 비동기적으로 실행되는 데 반해 useLayoutEffect는 브라우저가 DOM을 변경한 후, 화면에 변경 사항을 그리기 전(layout, paint 전)에 동기적으로 실행이 된다. 화면에 변경 사항을 그리기 이전에 실행하기에 컴포넌트 본연의 사이즈를 구하기 위해서는 useEffect보다 useLayoutEffect가 더 적합하다.
useLayoutEffect를 사용할 경우, 화면에 그리기 전 동기적으로 실행하기 때문에 사용자는 깜빡임을 보지 않는다.
</aside>

훅 안에서 width와 hegiht를 console을 찍어보았다(:17). 처음에 0 0은, 훅 자체는 컴포넌트가 마운트 되기 전에 실행되기 때문이다. 그리고 컴포넌트가 마운트 되면 handleResize가 실행되며 setComponentSize라는 setState함수가 실행이 된다. 이 떄 훅이 한 번 더 호출되는 것이다.