Props Drilling이란?
[Props Drilling]
상위 컴포넌트의 state를 props를 통해 전달하고자 하는 컴포넌트로 전달하기 위해 그 사이는 props를 전달하는 용도로만 쓰이는 컴포넌트들을 거치면서 데이터를 전달하는 현상이다. 위 그림처럼 컴포넌트 A의 state를 컴포넌트 D로 전달하기 위해선 사이에 있는 컴포넌트 B, C를 거쳐야 한다.
Props Drilling의 문제점
Props의 전달 횟수가 5회 이내로 많지 않다면 Props Drilling 은 큰 문제가 되지 않는다. 하지만 규모가 커지고 구조가 복잡해지면서 Props의 전달 과정이 늘어난다면 아래와 같은 문제가 발생한다.
- 코드의 가독성이 매우 나빠지게 된다.
- 데이터의 출처를 쉽게 파악할 수 없어서 코드의 유지보수 또한 힘들어지게 된다.
- 웹성능에 악영향을 줄 수 있다.
- (state 변경 시 Props 전달 과정에서 불필요하게 관여된 컴포넌트들 또한 리렌더링이 발생하기 때문)
해결 방법
과도한 Props Drilling을 방지하기 위한 방법으로는
- 컴포넌트와 관련 있는 state는 될 수 있으면 가까이 유지하는 방법과
- 상태관리 라이브러리를 사용하는 방법이 있다.
- 상태관리 라이브러리를 사용하게 되면 전역으로 관리하는 저장소에서 직접 state를 꺼내쓸 수 있기 때문에 Props Drilling을 방지하기에 매우 효과적이다.
- 상태관리 라이브러리로는 Redux, Context api, Mobx, Recoil 등이 있다.
데이터 무결성을 위해, 동일한 데이터는 항상 같은 곳에서 데이터를 가지고 오도록 해야한다. 상태 관리 라이브러리는 이 원칙 유지할 수 있게 도와준다. 상태 관리 라이브러리가 없어도 충분히 규모 있는 애플리케이션을 만들 수 있다. 하지만 규모가 커질수록 상태관리 라이브러리의 필요성이 높아진다. 또한, 상태의 출처에 대한 추적이 쉽기 때문에 코드의 가독성이 좋아지며, 디버깅이 용이해집니다.
Props Drilling 예시
예시 1
Props Drilling
아래의 예시는 props를 제일 깊은 컴포넌트까지 내려주어야 제대로 작동한다.
- 지금도 코드를 작성하는 게 번거롭고 복잡한데 이보다 더 깊은 컴포넌트와 복잡한 구조가 있다고 생각보면, 생각만 해도 끔찍하다.
- (코드를 보고 직접 props를 내려보자.)
- 이렇게 고치면 된다. (아래 더보기 클릭)
더보기
import React, { useState } from 'react';
import styled from 'styled-components';
const Container = styled.div`
border: 5px solid green;
padding: 10px;
margin: 10px;
position: relative;
`;
const Quantity = styled.div`
text-align: center;
color: red;
border: 5px solid red;
padding: 3px;
font-size: 1.2rem;
`;
const Button = styled.button`
margin-right: 5px;
`;
const Text = styled.div`
color: ${(props) => (props.color ? props.color : 'black')};
font-size: ${(props) => (props.size ? props.size : '1rem')};
font-weight: ${(props) => (props.weight ? '700' : 'inherit')};
`;
export default function App() {
const [number, setNumber] = useState(1);
const plusNum = () => {
setNumber(number + 1);
};
const minusNum = () => {
setNumber(number - 1);
};
console.log('Parents');
return (
<Container>
<Text weight size="1.5rem">
[Parents Component]
</Text>
<Text>
Child4 컴포넌트에 있는 버튼을 통해
<br /> state를 변경하려고 합니다.. 🤮
</Text>
<Text weight color="tomato">
Props Driling이 발생!!
</Text>
<Quantity>{`수량 : ${number}`}</Quantity>
<Child1 plusNum={plusNum} minusNum={minusNum} />
</Container>
);
}
function Child1(
{ plusNum, minusNum }
) {
console.log('Child1');
return (
<Container>
<Text>[Child 1 Component]</Text>
<Child2 plusNum={plusNum} minusNum={minusNum} />
</Container>
);
}
function Child2(
{ plusNum, minusNum }
) {
console.log('Child2');
return (
<Container>
<Text>[Child 2 Component]</Text>
<Child3 plusNum={plusNum} minusNum={minusNum} />
</Container>
);
}
function Child3(
{ plusNum, minusNum }
) {
console.log('Child3');
return (
<Container>
<Text>[Child 3 Component]</Text>
<Child4 plusNum={plusNum} minusNum={minusNum} />
</Container>
);
}
function Child4({ plusNum, minusNum }) {
console.log('Child4');
return (
<Container>
<Text>[Child 4 Component]</Text>
<Button onClick={plusNum}>👍</Button>
<Button onClick={minusNum}>👎</Button>
</Container>
);
}
상태관리 라이브러리 적용
이 현상을 해결할 수 있는 방법 중 하나는 상태관리 라이브러리를 사용하는 것이다.
- 아래의 예시는 상태관리 라이브러리 중 Redux를 활용한 예시이다.
- 상태관리 라이브러리를 사용 후 Props Drilling이 일어나지 않는다.
예시 2
Props Drilling으로 인한 불필요한 리렌더링
아래 예시는 Child6에 있는 👋 버튼을 누르면 Child3에 느낌표가 하나씩 추가되는 간단한 애플리케이션이다.
- 이때, Child3, Child6이 하나의 상태를 공유하기 때문에 최상위 컴포넌트인 App에서 상태를 관리해야 합니다.
- 이 때문에 상태를 변경할 때마다 App 컴포넌트가 리렌더링 되면서 모든 컴포넌트가 리렌더링 됩니다.
- 변경되는 상태와 연관이 없는 컴포넌트까지 불필요하게 리렌더링 되는 것이죠.
- 아래 예시에서 콘솔창을 열고 👋 버튼을 눌러 리렌더링 되는 컴포넌트를 확인하세요.
Redux의 리렌더링 최적화
Redux를 활용하여 전역 상태 관리를 할 수 있게 만들어주었다.
- 콘솔창을 열고 👋 버튼을 눌러 리렌더링 되는 컴포넌트를 확인하면,
- 상태의 영향을 받아 화면을 변경해야 하는 컴포넌트만 리렌더링 되는 것을 확인할 수 있다.
728x90
'FE > React' 카테고리의 다른 글
상태 관리 라이브러리 Redux (0) | 2023.04.24 |
---|---|
쇼핑몰 애플리케이션에서 Hooks를 이용한 상태 관리 (0) | 2023.04.24 |
[React] 전역 상태의 필요성 (0) | 2023.04.21 |
Styled Components로 ClickToEdit 만들기 (0) | 2023.04.20 |
Styled Components로 Tag 만들기 (0) | 2023.04.20 |