simkkong

[React] Prop Drilling 설명 및 컴포넌트 합성으로 해결하는 방법 본문

Develop/React

[React] Prop Drilling 설명 및 컴포넌트 합성으로 해결하는 방법

심꽁 2022. 12. 5. 12:50
728x90

React, Vue 등을 사용할 때, 원하는 상태인 state or data 값을 하위 컴포넌트(자식 컴포넌트)에게 넘겨주는 작업이 종종 발생한다. 이럴 때 prop drilling 이라는 용어가 나오게된다.
하위 컴포넌트가 매우 깊게 중첩될 경우에는, prop 값을 하위 컴포넌트의 하위 컴포넌트에게 넘겨주면서 관리하기가 어려워진다. 이러한 관리를 수월하게 할 수 있는 방법에 대해 설명하고자 한다.

 

Prop Drilling

Prop Drilling은 위의 설명처럼, state or data여러 하위 컴포넌트를 통과해 특정 하위 컴포넌트에게 전달하는 비공식 용어. 문제점은 넘겨주는 대부분의 하위 컴포넌트에 넘겨준 prop 값이 불필요한 값이란 것이다.
대략 3개의 하위 컴포넌트를 거치는 정도이면, 괜찮을 수 있도 있지만, 3개 이상을 거친다면 가독성이 떨어지고 유지보수가 어렵다.

 

예시는 아래와 같다.

import { useState } from "react";

function App() {
  const [user, setUser] = useState({ name: "Steve" });
  return (
    <div>
      <Navbar />
      <MainPage user={user} />
    </div>
  );
}
export default App;

// Navbar Component
function Navbar() {
  return <nav style={{ background: "#10ADDE", color: "#fff" }}>Demo App</nav>;
}

//MainPage Component
function MainPage({ user }) {
  return (
    <div>
      <h3>Main Page</h3>
      <Content user={user} />
    </div>
  );
}

// Content Component
function Content({ user }) {
  return (
    <div>
      <Message user={user} />
    </div>
  );
}

//Message Component
function Message({ user }) {
  return <p>Welcome {user.name}</p>;
}

user state 값을 Message 가 얻기위해, MainPage -> Content -> Message 가 호출되며 불필요한 user state 값을 MainPage 와 Content가 포함하게 된다.

 

이를 해결하기 위해 전역 상태관리 라이브러리 mobx, recoil, redux 등 사용할 수 있으며, 간단하게는 Context API 를 사용할 수 있다.

 

그러나 전역 상태관리 라이브러리를 설치하고 학습해야 하는 과정이 필요하며, Context API를 활용할 경우, 컴포넌트가 재활용이 어려워진다는 단점이 생겨난다.

더욱 간단한 방법으로는 Component Composition (컴포넌트 합성)을 사용할 수 있다.

 

리액트는 컴포넌트의 조합을 중시하며, 컴포넌트 또한 Javascript처럼 객체일 뿐이다. 그래서 prop 에 컴포넌트도 포함이 된다.

 

1. 전달하고자 하는 컴포넌트를, 다른 컴포넌트에 prop으로 전달하여 원하는 하위 컴포넌트 내에서 prop으로 꺼내어 사용하거나 렌더링할 수 있다.

2. 상위 컴포넌트에서 하위 컴포넌트에 계속해서 하위 컴포넌트를 래핑하여 prop으로 전달해서, 원하는 하위 컴포넌트에 prop 값을 넘겨준다.

 

첫 번쨰 방법은 아래와 같다.

import {useState} from 'react'

function App() {
  const [data, setData] = useState("some state");
  return <ComponentOne ComponentTwo={<ComponentTwo data={data} />} />;
}

function ComponentOne({ ComponentTwo }) {
  return (
    <div>
      <p>This is Component1, it receives component2 as a prop and renders it</p>
      {ComponentTwo}
    </div>
  );
}

function ComponentTwo({ data }) {
  return <h3>This is Component two with the received state {data}</h3>;
}

 

중첩된 하위 컴포넌트 ComponentTwo 에게 data prop을 전달하기 위해, ComponentOne의 prop에 ComponentTwo 컴포넌트 자체를 넘기면서 App 컴포넌트 안에서 원하는 ComponentTwo의 data prop에 직접 값을 넣어주는 방식인 것이다.
하위 컴폰넌트를 root Level로 올릴 수 있다는 것과, 어떤 컴포넌트가 들어갈 것인지가 예측된다는 장점이 생긴다.

 

두 번째 방법은 아래와 같다.

function App() {
  const [data, setData] = useState("some state");

  return (
    <ParentComponent>
      <ComponentOne>
        <ComponentTwo data={data} />
      </ComponentOne>
    </ParentComponent>
  );
}

function ParentComponent({ children }) {
  return <div>{children}</div>;
}
function ComponentOne({ children }) {
  return (
    <>
      <p>This is Component1, it receives component2 as a child and renders it</p>
      {children}
    </>
  );
}

function ComponentTwo({ data }) {
  return <h3>This is Component two with the received {data}</h3>;
}

ParentComponent와 ComponentOne은 넘겨주는 children 객체 prop 만 관리하면 되며, children이 여러 개든 한개든 아예 없든 크게 신경쓰지 않으며 children을 유연하게 넘겨받는다. 마찬가지로 ComponentTwo는 App root Level에서 data state 를 직접 전달받을 수 있게된다.


이러한 간단한 Component Composition 방법을 통해, 위에서 문제가 된 Prop Drillling 예시를 아래와 같이 변경할 수 있다.

function App() {
  const [user, setState] = useState({ name: "Steve" });
  return (
    <div>
      <Navbar />
      <MainPage>
        <Content>
          <Message user={user} />
        </Content>
      </MainPage>
    </div>
  );
}
export default App;

function Navbar() {
  return <nav style={{ background: "#10ADDE", color: "#fff" }}>Demo App</nav>;
}

function MainPage({ children }) {
  return (
    <div>
      <h3>Main Page</h3>
      {children}
    </div>
  );
}

function Content({ children }) {
  return <div>{children}</div>;
}

function Message({ user }) {
  return <p>Welcome {user.name} :)</p>;
}

 

 


참고사이트

https://blog.logrocket.com/solving-prop-drilling-react-apps/#container-components

 

A better way of solving prop drilling in React apps - LogRocket Blog

In the spirit of "using the platform," learn how the React library provides a workaround for prop drilling without Redux or the Context API.

blog.logrocket.com

 

https://velog.io/@jangws/React-Context가-꼭-필요할까-컴포넌트-합성으로-props-drilling을-극복해보자

 

[React] Context가 꼭 필요할까? 컴포넌트 합성으로 props drilling을 극복해보자

Prop Drilling은 props를 오로지 하위 컴포넌트로 전달하는 용도로만 쓰이는 컴포넌트들을 거치면서 React Component 트리의 한 부분에서 다른 부분으로 데이터를 전달하는 과정이다.prop drilling이 보통 3~5

velog.io

 

Comments