1. 문제상황
부모 컴포넌트에서 어떤 데이터를 조회 받아올때 마다 자식 컴포넌트인 bottomSheet
의 높이State
가 초기화 되는 현상이 일어났다.
React의 리렌더링 조건은 크게 2가지로 볼 수 있다.
- 부모 컴포넌트가 리렌더링을 하게 되면 자식 컴포넌트들은 리렌더링 된다.
state
가 변경되면 해당 컴포넌트는 리렌더링 된다.
이 상황의 경우 부모 컴포넌트가 리렌더링 되는 경우 자식 컴포넌트들은 리렌더링 되는 경우이다.
부모 컴포넌트에서 데이터를 조회 받아와 지도에 적용을 하게 되면서 리렌더링이 발생하고, 자식 컴포넌트인 bottomSheet
컴포넌트도 리렌더링을 하면서 높이State
가 초기화 되는 것이다.
상황 이해를 위하여 코드예제를 보도록하자.
// ParentComponent.jsx
import React, { useState } from 'react';
import ChildComponent from './ChildComponent';
const ParentComponent = () => {
const [count, setCount] = useState(0);
return (
<div>
<h2>부모 컴포넌트</h2>
<button onClick={() => setCount(count + 1)}>
카운트 증가: {count}
</button>
<ChildComponent />
</div>
);
};
export default ParentComponent;
// ChildComponent.jsx
import React, { useState, useEffect } from 'react';
const ChildComponent = () => {
const [height, setHeight] = useState(200);
// 높이 조절 함수
const increaseHeight = () => {
setHeight(prevHeight => prevHeight + 20);
};
return (
<div
style={{
height: `${height}px`,
backgroundColor: 'lightblue',
transition: 'height 0.3s ease',
marginTop: '20px',
padding: '10px'
}}
>
<h3>자식 컴포넌트</h3>
<p>현재 높이: {height}px</p>
<button onClick={increaseHeight}>높이 증가</button>
</div>
);
};
export default ChildComponent;
간략히 부모 컴포넌트는 count
를 증가할 수 있고, 해당 count
를 state
로 가지고 표현 한다.
자식 컴포넌트는 높이를 조절할 수 있는 bottomSheet
라고 생각할 때 손으로 터치해서 높이를 변경 해놓았는데, 부모 컴포넌트에서 count증가 버튼을 누르면 count state
가 변경되어 자식 컴포넌트도 초기화 되면서 height
도 변경되게 된다.
2. 해결 방법
이 문제를 어떻게 해결할 수 있을까?
기본적인 React에서 해결방법은 useCallback
과 memo
로 컴포넌트를 감싸 리렌더링을 막는 방법을 많이 사용하곤 한다.
하지만 위 예제에서는 bottomSheet
에서 특정 조건에 따라 리렌더링 해야하는 경우들이 많다.
const BottomSheet: React.FC<BottomSheetProps> = React.memo(
({ slopeData, selectItem, onItemClick }) => {
//컴포넌트 내용
//컴포넌트 내용
//컴포넌트 내용
//컴포넌트 내용
,(prevProps, nextProps) => {
// slopeData의 실제 내용 비교
const prevIds = prevProps.slopeData.map((slope) => slope._id);
const nextIds = nextProps.slopeData.map((slope) => slope._id);
return (
prevIds.length === nextIds.length &&
prevIds.every((id, index) => id === nextIds[index])
);
}
);
)
코드에서 확인할 수 있듯이 memo조건으로 상황별로 빠지는 부분없이 전부를 체크해서 추가해줘야하는 번거로움이 발생한다.
그저 리렌더링 문제를 막고자 useCallback
과 memo
를 사용부터 하는 것이 아니라, 리렌더링 최적화 하기 전에는 고민을 먼저 하는 것이 좋다.
부모 컴포넌트가 리렌더링을 하면서 자식 컴포넌트들이 리렌더링이 되기 때문에 컴포넌트 분리를 통해서 자식 컴포넌트가 아닌 형제 컴포넌트로 구조를 변경하여 리렌더링 최적화를 진행할 수 있고 State 끌어올리기를 통해서도 최적화를 진행할 수 있다.
useCallback
과 memo
를 사용한 방법 뿐만 아니라 여러 다양한 리렌더링 최적화 방법이 존재한다.
State(상태) 끌어올리기
State 끌어올리기는 말 그대로 자식 컴포넌트에 존재하는 State를 부모 컴포넌트로 올리는 것을 말한다.
부모 컴포넌트 리렌더링 때문에, 자식 컴포넌트에서 유지되어야 하는 state가 유지 되지 않고 초기화 되는 경우 state를 부모로 올려 자식에게 전달하는 방법을 말한다.
// ParentComponent.jsx
import React, { useState } from 'react';
import ChildComponent from './ChildComponent';
const ParentComponent = () => {
const [count, setCount] = useState(0);
const [height, setHeight] = useState(200); // 상태를 부모로 끌어올림
return (
<div>
<h2>부모 컴포넌트</h2>
<button onClick={() => setCount(count + 1)}>
카운트 증가: {count}
</button>
<ChildComponent
height={height}
setHeight={setHeight}
/>
</div>
);
};
export default ParentComponent;
// ChildComponent.jsx
import React from 'react';
// props로 height와 setHeight를 받음
const ChildComponent = ({ height, setHeight }) => {
// 높이 조절 함수
const increaseHeight = () => {
setHeight(prevHeight => prevHeight + 20);
};
console.log("자식 컴포넌트 렌더링 - 현재 높이:", height);
return (
<div
style={{
height: `${height}px`,
backgroundColor: 'lightblue',
transition: 'height 0.3s ease',
marginTop: '20px',
padding: '10px'
}}
>
<h3>자식 컴포넌트</h3>
<p>현재 높이: {height}px</p>
<button onClick={increaseHeight}>높이 증가</button>
</div>
);
};
export default ChildComponent;
height
State를 부모 컴포넌트로 올리고, props로 다시 자식 컴포넌트에게 전달하도록 State끌어올리기를 진행한다면, 부모 컴포넌트에서 리렌더링이 발생한다고 하더라도 heightState가 변경되지 않고 유지된다.
하지만 State 끌어올리기는 말 그대로 State만 부모로 전달한 것이기 때문에 렌더링 횟수와 성능은 그대로이다. 그렇기에 성능 관련 리렌더링 문제인 경우 State 끌어올리기가 해결책이 되지 않을 수 있다.
이처럼 리렌더링 문제에 직면하게 된 경우 생각 없이 useCallback
과 memo
부터 사용하는 것이 아닌, 발생한 문제가 무엇인지 정확히 인지하고 다양한 방법으로 해결하는 것이 중요하다.
'React' 카테고리의 다른 글
[Vite] vite.config.js 설정 (proxy, console제거) (0) | 2025.05.26 |
---|---|
[React] 사진 슬라이드 쉽게 직접 구현하기 (0) | 2025.05.18 |
[React] GlobalStyle 폰트 적용 안됨, 폰트 깜빡임 현상 원인 및 해결방법 (0) | 2025.04.14 |
[React] 페이지 있는 게시판 리스트 만들기 (styled-components) (2) | 2024.12.15 |
[React.js] 리액트 반응형 구현 (styled-component,media query, grid를 곁들인) (2) | 2024.11.12 |