리액트에서 ref를 사용해서 리스트 로딩이 완료된 후 컴포넌트의 높이를 가져오는 방법
> 데이터 로딩이 완료되어 컴포넌트가 다시 렌더링된 시점에 높이를 측정한다. 이를 위해서 useEffect 훅을 데이터 (state)와 연결하여 사용한다.
# 원리 : 데이터 로딩 -> state 변경 -> 컴포넌트 리렌더링 -> useEffect 실행 -> ref.current로 DOM 요소에 접근해 높이 측정
1. useRef
높이를 측정하고 싶은 DOM 요소에 연결할 ref 객체를 생성한다.
2. useState
리스트 데이터와 로딩 상태를 관리한다.
3. useEffect
데이터가 변경되어 리렌더링이 완료된 후에 특정 작업을 수행한다.
이 useEffect의 의존성 배열에 데이터 state를 넣어주는 것이 핵심이다.
import React, { useState, useEffect, useRef } from 'react';
function ListComponent(){
// 1. 상태 관리 : 데이터, 로딩상태, 측정된 높이
const [data, setData] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [componentHeight, setComponentHeight] = useState(0);
// 2. ref 생성 : 높이를 측정할 DOM 요소에 연결
const listContainerRef = useRef(null);
// 3. 데이터 로딩을 위한 useEffect ( 컴포넌트 마운트 시 1회 실행 )
useEffect(()=>{
// 비동기 데이터 로딩 시뮬레이션 ( 예시 : api 호출 )
setTimeout(()=>{
const fetchedData = ['apple', 'banana', 'cherry', 'date', 'elderberry'];
setData(fetchedData);
setIsLoading(false);
}, 1500);
},[]); // 의존성 배열이 비어있으므로 최초 렌더링 시에만 실행
// 4. 높이 측정을 위한 useEffect (data가 변경될 때마다 실행)
useEffect(()=>{
// 데이터 로딩이 완료되고, ref가 DOM에 연결되었다면 높이 측정
if(!isLoading && listContainerRef.current){
const height = listContainerRef.current.offsetHeight;
setComponentHeight(height);
console.log(`리스트 로드 완료! 측정된 높이 : ${height}px`);
}
},[data, isLoading]);
return(
<div>
<h1>과일 리스트</h1>
<p>측정된 컨테이너 높이: <strong>{componentHeight}px</strong></p>
{/* 이 div의 높이를 측정합니다 */}
<div ref={listContainerRef} style={{ border: '2px solid blue', padding: '10px' }}>
{isLoading ? (
<p>리스트를 불러오는 중...</p>
) : (
<ul>
{data.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
)}
</div>
</div>
);
}
export default ListComponent;
# 동작 요약
listContainerRef: useRef(null)로 ref 객체를 만듭니다. 이 객체는 나중에 <div> 요소의 참조를 갖게 됩니다. JSX 부분의 <div ref={listContainerRef}>를 통해 연결됩니다.
- 데이터 로딩 useEffect: 컴포넌트가 처음 생길 때([]) 데이터를 불러옵니다. 데이터 로딩이 성공하면 setData를 호출해 data 상태를 업데이트합니다.
- 상태 업데이트와 리렌더링: data 상태가 바뀌면 ListComponent는 새로운 data로 리렌더링됩니다. 이때 <ul>과 <li>들이 실제로 화면에 그려집니다.
- 높이 측정 useEffect: 이 useEffect는 의존성 배열에 [data, isLoading]이 있으므로 data나 isLoading 상태가 바뀔 때마다 실행됩니다.
- 데이터 로딩이 완료되면 (!isLoading), 컴포넌트는 이미 리렌더링되어 화면에 모든 <li>가 그려진 상태입니다.
- 이 시점에서 listContainerRef.current는 <div> DOM 요소를 가리키고 있으므로, .offsetHeight를 통해 정확한 높이를 가져올 수 있습니다.
> 만약에 높이를 측정한 후 즉시 다른 dom 관련 작업을 수행해야해서 미세한 깜빡임도 허용하고 싶지 않다면, useEffect 대신에 useLayoutEffect를 통해서 정확한 높이를 가져올 수 있다.
- useEffect는 브라우저가 화면을 그린 후에 비동기적으로 실행되지만
- useLayoutEffect는 DOM 업데이트는 완료되었지만 브라우저가 화면을 그리기 전에 동기적으로 실행된다.
사용법은 useEffect를 그냥 useLayoutEffect로 바꾸면 된다. DOM 크기나 위치를 측정하는 작업에는 useLayoutEffect가 더 적합할 때가 많다.
import { useLayoutEffect } from 'react';
// ...
// 높이 측정을 위한 useLayoutEffect
useLayoutEffect(() => {
if (!isLoading && listContainerRef.current) {
const height = listContainerRef.current.offsetHeight;
setComponentHeight(height);
}
}, [data, isLoading]);
'Frontend' 카테고리의 다른 글
왜 api 베이스에 서버 IP주소를 그대로 넣으면 안되는가 (0) | 2025.06.27 |
---|---|
페이지 단위로 스크롤 끊기 (0) | 2025.04.24 |
글 올라가는 효과 (0) | 2025.04.24 |
Axios Interceptor, Lodash.debounce (0) | 2025.04.15 |
css -> tailwind css (0) | 2025.03.28 |