본문 바로가기

Props Drilling이란?

Props Drilling이란?

 

 

Props Drilling이란?

 

[Props Drilling]

상위 컴포넌트의 state를 props를 통해 전달하고자 하는 컴포넌트로 전달하기 위해 그 사이는 props를 전달하는 용도로만 쓰이는 컴포넌트들을 거치면서 데이터를 전달하는 현상이다. 위 그림처럼 컴포넌트 A의 state를 컴포넌트 D로 전달하기 위해선 사이에 있는 컴포넌트 B, C를 거쳐야 한다.
 

Props Drilling의 문제점

 

Props의 전달 횟수가 5회 이내로 많지 않다면 Props Drilling 은 큰 문제가 되지 않는다. 하지만 규모가 커지고 구조가 복잡해지면서 Props의 전달 과정이 늘어난다면 아래와 같은 문제가 발생한다.

  • 코드의 가독성이 매우 나빠지게 된다.
  • 데이터의 출처를 쉽게 파악할 수 없어서 코드의 유지보수 또한 힘들어지게 된다.
  • 웹성능에 악영향을 줄 수 있다.
    • (state 변경 시 Props 전달 과정에서 불필요하게 관여된 컴포넌트들 또한 리렌더링이 발생하기 때문)

해결 방법

 

과도한 Props Drilling을 방지하기 위한 방법으로는

  1. 컴포넌트와 관련 있는 state는 될 수 있으면 가까이 유지하는 방법과
  2. 상태관리 라이브러리를 사용하는 방법이 있다.
    • 상태관리 라이브러리를 사용하게 되면 전역으로 관리하는 저장소에서 직접 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
⬆︎