728x90
728x90
useLayoutEffect 훅
들어가며
- 리액트(React.js)의 @useLayoutEffect@ 훅에 대해 간단히 정리해본다.

useLayoutEffect 훅
개념
- 컴포넌트가 렌더링되기 직전, 즉 브라우저가 화면을 그리기 전에 실행되는 훅
- 화면에 변화가 나타나기 전에 어떠한 처리를 하고 싶을 때 사용한다.
사용 방법
import { useLayoutEffect } from 'react';
useLayoutEffect(() => {
// 레이아웃 관련 변경, 동기적 DOM 조작 등에 사용한다.
}, [dependencies]);
useEffect 훅과 비교하기
| 항목 | useEffect 훅 | useLayoutEffect 훅 |
| 실행 시점 | 컴포넌트 렌더링 후, 브라우저가 화면을 그린 뒤 | 컴포넌트 렌더링 직후, 브라우저가 화면을 그리기 직전 |
| 비동기 | 비동기적 (렌더링 완료 후 실행됨.) | 동기적 (DOM 변경 전에 실행됨.) |
| 사용 목적 | API 호출, 이벤트 리스너 등록 등 비시각적 처리 | DOM 측정, 스타일 계산, 스크롤 위치 변경 등 시각적 처리 |
| UI 깜빡임 | 가능성 있음 (스타일이 나중에 바뀔 수 있음) | 없음 (변경이 화면 그리기 전에 적용됨) |
| 브라우저 화면 렌더링 방해 여부 | 없음 | 있음 (렌더링 블로킹 가능성 있음.) |
useLayoutEffect 훅을 사용하면 성능이 저하될 수 있으므로, 가능하면 useEffect 훅을 사용한다.
언제 @useLayoutEffect@를 써야 할까?
- DOM 크기 측정 (@offsetWidth@, @getBoundingClientRect@ 등)
- 스타일이나 레이아웃 조작
- 스크롤 위치 조정
- React Navigation 라이브러리를 이용할 때, @navigation.setOptions()@처럼 초기 렌더 타이틀이 깔끔하게 반영되어야 하는 경우 [React Native]
useLayoutEffect(() => {
navigation.setOptions({
title: '동적으로 설정된 제목',
});
}, [navigation]);
예제 코드 비교해보기
useEffect(() => {
console.log('useEffect 실행');
}, []);
useLayoutEffect(() => {
console.log('useLayoutEffect 실행');
}, []);
⇒ ①컴포넌트 함수 실행 → ②@useLayoutEffect@ 훅 실행 → ③브라우저가 화면을 그림 → ④@useEffect@ 훅 실행
정리
- @useLayoutEffect@ 훅은 컴포넌트가 렌더링되기 직전(브라우저가 화면을 그리기 전) 실행되는 훅이다.
- 데이터 페칭, 로그 출력, 이벤트 핸들링 등의 작업을 할 때는 @useEffect@ 훅을 사용한다.
- 레이아웃 관련 조작, DOM 크기 측정, 애니메이션 초기값을 설정할 때는 @useLayoutEffect@ 훅을 사용한다.
예제 코드
[React Native] 초기 렌더링 시, 스크린 타이틀이 깔끔하게 반영되도록 하기
import { useLayoutEffect } from 'react';
import { View, StyleSheet, FlatList, Text } from 'react-native';
import { MEALS, CATEGORIES } from '../data/dummy-data';
import MealItem from '../components/MealItem';
function MealsOverviewScreen({ route, navigation }) {
const categoryId = route.params.categoryId; // 파라미터 값 가져오기
const displayedMeals = MEALS.filter((mealItem) => {
return mealItem.categoryIds.indexOf(categoryId) >= 0; // 데이터가 있는 항목만 필터링
});
// 동적으로 스크린 이름 지정하기
useLayoutEffect(() => {
const categoryTitle = CATEGORIES.find(
(category) => category.id === categoryId
).title;
navigation.setOptions({
title: categoryTitle,
});
}, [categoryId, navigation]);
// 아이템 렌더링
function renderMealItem(itemData) {
const item = itemData.item;
const mealItemProps = {
title: item.title,
imageUrl: item.imageUrl,
duration: item.duration,
complexity: item.complexity,
affordability: item.affordability,
};
return <MealItem {...mealItemProps} />;
}
return (
<View style={styles.container}>
<FlatList
data={displayedMeals}
keyExtractor={(item) => item.id}
renderItem={renderMealItem}
/>
</View>
);
}
export default MealsOverviewScreen;
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
},
});
[React] API 요청 후 데이터 표시하기
import { useState, useEffect } from 'react';
function UserList() {
const [users, setUsers] = useState([]);
const [isLoading, setIsLoading] = useState(true);
// 컴포넌트 마운트 시 API 호출
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then((res) => res.json())
.then((data) => {
setUsers(data);
setIsLoading(false);
})
.catch((error) => {
console.error('에러 발생:', error);
setIsLoading(false);
});
}, []);
return (
<div>
<h2>사용자 목록</h2>
{isLoading ? (
<p>로딩 중...</p>
) : (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name} ({user.email})</li>
))}
</ul>
)}
</div>
);
}
export default UserList;
[React] @<div>@ 요소의 크기를 파악하고 레이아웃 관련 작업하기
import { useRef, useState, useLayoutEffect } from 'react';
function Box() {
const boxRef = useRef(null);
const [width, setWidth] = useState(0);
useLayoutEffect(() => {
if (boxRef.current) {
const boxWidth = boxRef.current.getBoundingClientRect().width;
setWidth(boxWidth); // DOM 읽고 상태 설정 (동기 작업)
}
}, []);
return (
<div>
<div
ref={boxRef}
style={{
width: '50%',
height: '100px',
backgroundColor: 'skyblue',
}}
>
박스
</div>
<p>박스의 너비는 {width}px 입니다.</p>
</div>
);
}
export default Box;
참고 사이트
useEffect – React
The library for web and native user interfaces
ko.react.dev
useLayoutEffect – React
The library for web and native user interfaces
ko.react.dev
728x90
728x90
'Programming > React' 카테고리의 다른 글
| [React.js] 폼(Form) 처리 방법 (React 19) (0) | 2025.01.21 |
|---|---|
| [React.js] React Hook Form 라이브러리 (0) | 2024.11.23 |
| [React.js] 객체 표기법(Object Notation) 방식과 빌더 콜백 표기법(Builder Callback Notation) 방식 (0) | 2024.11.13 |
| [React.js] .js 파일에서 Uncaught SyntaxError: Unexpected token '<' 오류 발생할 때 해결 방법 (Vite) (0) | 2024.11.13 |
| [React.js] <Link> 컴포넌트와 <NavLink> 컴포넌트 비교 (React Router) (0) | 2024.11.13 |
| [React.js] 리덕스(Redux), 리덕스 툴킷(Redux Toolkit) (0) | 2024.11.11 |
| [React.js] 모든 웹 브라우저에서 공통된 HTML 요소 스타일이 보여지도록 설정하는 방법 (normalize.css) (0) | 2024.11.07 |
| [React.js] Recharts 라이브러리 (1) | 2024.11.06 |