Props Drilling은 props를 오로지 하위 컴포넌트로 전달하는 용도로만 쓰이는 컴포넌트를 거치면서 React Comoinnt트리의 한 부분에서 다른 부분으로 데이터를 전달하는 과정이다.
import React from "react";
import "./styles.css";
export default function App() {
return (
<div className="App">
<FirstComponent content="Who needs me?" />
</div>
);
}
function FirstComponent({ content }) {
return (
<div>
<h3>I am the first component</h3>;
<SecondComponent content={content} />|
</div>
);
}
function SecondComponent({ content }) {
return (
<div>
<h3>I am the second component</h3>;
<ThirdComponent content={content} />
</div>
);
}
function ThirdComponent({ content }) {
return (
<div>
<h3>I am the third component</h3>;
<ComponentNeedingProps content={content} />
</div>
);
}
function ComponentNeedingProps({ content }) {
return <h3>{content}</h3>;
}
componentNeedingProps 컴포넌트에서 해당 props를 사용하기 위해 content를 전달하는 과정으로 App > first > second > third > componentNeedingProps
순이 되겠다.
먼저, props 전달이 3~5개 정도 컴포넌트라면 Props Drilling은 문제가 되지 않는다. 하지만 Props 전달이 10개, 15개 같이 더 많은 과정을 거치게 된다면 어떻게 될까? 코드를 읽을 때 해당 props를 추적하기가 힘들어진다.
redux, Mobx, recoil 등을 사용하여 해당 값이 필요한 컴포넌트에서 직접 불러서 사용할 수 있다.
공식문서에서는 아래와 같이 설명하고 있다.
어떤 컴포넌트들은 어떤 자식 엘리먼트가 들어올지 미리 예상할 수 없는 경우가 있습니다. 범용적인 '박스'역할을 하는 sidebar혹은 Dialog와 같은 컴포넌트에서 특히 자주 볼 수 있다.
이게 도대체 무슨 말일까..? 여러 블로그나 다른 개발자들의 말을 빌려 이야기 하자면,
태그와 태그 사이의 모든 내용을 표시하기 위해 사용되는 특수한 Porops
다음은 생명주기 및 데이터를 변경하지 않고 Props.children을 화면에 표시하는 간단한 컴포넌트이다.
cosnt Category = (props) => {
return <ul>{props.children}</ul>
}
children은 특수한 속성이므로 아래와 같이 작성할 수도 있다.
cosnt Category = ({children}) => {
return <ul>{children}</ul>
}
다음은 위에서 작성한 Category 컴포넌트를 사용하는 App 컴포넌트이다.
const App = () => (
<Category>
<li>First item.</li>
<li>Second item.</li>
<li>Another item.</li>
</Category>
);
실행 결과
App 컴포넌트에서 작성한 < Category > ~ < /Category > 내부에 작성한 내용들이 Category 컴포넌트에게 props.children으로 전달되게 된다.
{props.children}은 < Category > ~ < /Category > 내부에 작성된 내용들을 화면에 표시한다.
props.children은 주로 자식 컴포넌트 또는 html 엘리먼트가 어떻게 구성되어있는지 모르는데 화면에 표시해야 하는 경우 사용한다.
예를 들어 < Category > ~ < /Category >안에 < li >가 몇 개 작성될지 모른다면 효율적으로 사용할 수 있게 되는 것이다.
const App =() => {
<Category>
{/* li 태그가 0개일 수도 있고 여러 개일 수도 있습니다.}
<li>First item.</li>
<li>Second item.</li>
<li>Another item.</li>
</Category>
}
props.children의 사용시 주의할 사항으로는 태그와 태그 사이의 모든 요소들을 자식취급하지 않는다는 것이다.
아래 코드에서 Category 컴포넌트의 자식 요소는 < ul >엘리먼트이다.
const li_Array = ["First item.", "Second item."];
const App = () => (
<Category>
<ul>
{li_Array.map((value, idx) => (
<li key={idx}>{value}</li>
))}
</ul>
</Category>
);
< ul > ~ < /ul > 사이에 있는 < li > 엘리먼트는 < Category > 기준으로는 자손이며, < ul > 기준으로는 자식 엘리먼트이다. React에서 자식의 개수를 반환하는 React.children.count 함수를 사용하여 Category컴포넌트의 자식의 개수를 확인해보면 1개만 출력되는 것을 확인할 수 있다.
앞서 Props Drilling으로 만들었던 예제코드를 children으로 바꿔보자.
import React from "react";
import "./styles.css";
export default function App() {
const content = "Who needs me?";
return (
<div className="App">
<FirstComponent>
<SecondComponent>
<ThirdComponent>
<ComponentNeedingProps content={content} />
</ThirdComponent>
</SecondComponent>
</FirstComponent>
</div>
);
}
function FirstComponent({ children }) {
return (
<div>
<h3>I am the first component</h3>;
{ children }
</div>
);
}
function SecondComponent({ children }) {
return (
<div>
<h3>I am the second component</h3>;
{children}
</div>
);
}
function ThirdComponent({ children }) {
return (
<div>
<h3>I am the third component</h3>
{children}
</div>
);
}
function ComponentNeedingProps({ content }) {
return <h3>{content}</h3>
}
위에서 보았던 Props Drilling을 이와 같이 리팩토링으로 진행한다면 하나의 컴포넌트에서 값을 관리하고, 그 값을 하위요소로 전달할 때 코드의 추적이 어려워지지 않게 된다.
reference
Props Drilling
Props Children
안녕하세요
새로운 기술이 있어서 참고하시라고 글 남겨요.
React, Vue, Angular에서 Props 드릴링 문제는 BindModel을 통해 한 번에 해결할 수 있습니다. BindModel은 데이터를 중앙에서 관리하고 비즈니스 로직을 명확하게 분리하여 유지 관리와 재사용성을 크게 개선합니다.
BindModel의 구성 요소인 MetaTable과 MetaView는 표준 인터페이스로 정의되어 화면 구성이 더 유연해집니다. React와 Vue는 화면 관련 책임만 관리하고 비즈니스 로직을 BindModel에 위임하여 다양한 화면에서 비즈니스 로직을 재사용할 수 있습니다.
궁금하신점 있으시면 연락주셔요. 수고하세요.
bindmodel@gmail.com
예제 git : https://github.com/white-base/exam-bind-model.git
참고 : https://bindmodel.com/exam/notice/