"Props Drilling 지우기" 글과 관련해서 의견을 나누고 싶어요. #29
Replies: 5 comments 7 replies
-
안녕하세요 @jungpaeng 님, 소중한 의견 남겨주셔서 감사해요!
예시) <ContextProvider>
<MemorizedParentComponent>
<ChildComponentUsingContext /> <- 값이 변경되면, 해당 컴포넌트만 리렌더링이 됩니다.
</MemorizedParentComponent>
</ContextProvider/>
제안주신 예시를 사용하면, 오해를 줄이고, 메세지가 효과적으로 전달될 것 같은데요. |
Beta Was this translation helpful? Give feedback.
-
@Kimbangg 이 부분에 대해서 혹시 어떤 게 잘못된 인식이라고 생각하는지 알 수 있을까요? ContextAPI는 전달 통로 역할을 하기 때문에 props drilling을 해결하기 위해서 Context API를 사용하는 것은 어색하지 않을 것 같아요. 공식 문서에서도 props drilling 문제를 해결하기 위해서 ContextAPI 사용을 제시하고 있기도 하고요. 잘못된 인식을 생각해보면 그렇지만 남겨주신 예시 코드를 보면 이것을 우려한 것은 아니고 Context의 영향 범위가 아닌 코드가 리렌더링되는 것에 대해서 우려하고 계신 것 같아요. 이게 맞다면 저는 이 부분에 대해서는 '크게 걱정할 부분이 아니다' 라고 생각해요. 이렇게 생각한 부분에 대해서는 여러 이유가 있는데요.
또한, dan abramov를 비롯한 많은 리액트 / 프레임워크 개발자들이 리액트의 재조정 단계는 매우 빠르며, 이는 무시할만한 수치라고 의견을 남기기도 했어요(이제 다시 와서 재조정 횟수를 가지고 퍼포먼스 측도를 판단하는 흐름이 찾아오고 있는 것 같지만..). ContextAPI가 redux, zustand, jotai와 비교되면서 '리렌더링을 더 많이 발생시키는 안 좋은 기능'이라고 평가 받는 것도 많이 봐왔지만 대부분은 오해라고 생각하기도 하구요. |
Beta Was this translation helpful? Give feedback.
-
@jungpaeng 님, 상세한 답변 정말 감사합니다.
말씀 주신 대로 “리렌더링”이라는 표현을 넓게 사용하다 보니 이런 오해가 생겼던 것 같습니다. :)
질문으로 돌아가, “Props Drilling 해결 = Context API 사용”이 잘못된 인식이라고 생각했던 이유를 곰곰이 돌아보았습니다. 위 예시와 같이, 부모 컴포넌트가 1~2개의 자녀를 가지는 경우에는 말씀하신 대로 성능에 큰 영향을 미치지 않을 것 같습니다. 따라서 Context API 사용 자체에 대한 반감을 키우고 싶다기 보다는, 해당 글을 통해 Context API를 언제, 어떻게 사용하는 것인지 함께 다뤄볼 수 있으면 더더욱 좋을 것 같습니다. @jungpaeng 님께서 가지고 계신 생각을 명확하고 이해하기 쉽게 전달해 주셔서 감사드립니다. |
Beta Was this translation helpful? Give feedback.
-
전역 상태에 관한 열띈 토론이 이어지고 있네요 👀 |
Beta Was this translation helpful? Give feedback.
-
props drilling 및 위 의견과 관련해 좀 더 의견을 덧대고 싶어 글 남깁니다. 위 글이 불필요한 코드의 수정이 많이 일어난다는 단점에 공감하고 있다고 생각해요. 개발하면서 props drilling이 물론 불필요한 코드 작성이 많이 들었던것은 맞고 충분히 공감하는 바이지만, 위 글에서 드러내고싶어 했던 불필요한 결합도 측면에서 조금 더 보충될 수 있을 것 같습니다. ItemEditModal 컴포넌트와 ItemEditList 사이에 Item이라는 맥락과 관계없는, 예를 들어 FormBody라는 컴포넌트가 렌더링 된다면 불필요한 "결합도"가 생긴다는 점이 더 부각될 것 같아요. ItemEditList에 prop을 전달해주기 위해 FormBody에 Item이라는 맥락과 관련된 불필요한 결합이 생겨버릴 수 있어요. function FormBody({
keyword,
onKeywordChange,
items, // props drilling으로 인해
recommendedItems, // FormBody에게는 부적절한 맥락이 주입되는 경우
onConfirm,
onClose
}) {
return (
<>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<Input
value={keyword}
onChange={(e) => onKeywordChange(e.target.value)}
/>
<Button onClick={onClose}>닫기</Button>
</div>
<ItemEditList
keyword={keyword}
items={items}
recommendedItems={recommendedItems}
onConfirm={onConfirm}
/>
</>
);
} 물론 경험이 많은 개발자들은 FormBody라는 낮은 수준의 맥락이 적용되는 컴포넌트에 ItemEditList를 직접 렌더링하지 않겠지만, 경험이 적거나 내부적으로 다양한 맥락이 뒤엉키는 SideBar 같은 UI에서는 하기 쉬운 실수라고 생각해요. 그리고 반대로 props driling을 피하려고 맥락을 부정확하게 정하게 될 수도 있을 것 같아요. 예를 들어 FormBody라는 컴포넌트는 사실 Item에만 적용되는 것도 아니라 다른 도메인에도 적용될 수 있는데, ItemFormBody라고 이름지어 그 맥락만 갖게 하는 경우가 있을 수 있어요. 이러면 당장 Item의 경우에는 컴포넌트를 인식하는 맥락(이름)과 실제 맥락(props와 렌더링 결과)이 자연스럽지만 다른 도메인에 작성하기 위해 중복 코드를 작성하는 문제가 생겨요. 이런 경우 위에서 제시해주신 것과 같이 drilling이 얕은 경우 children prop을 통해 내부 렌더링 방식을 드러내도록 할 수 있을 것 같아요. 아니면은 Form과 같이 기능이 적용되는 컴포넌트이면서 맥락이 적은 컴포넌트라면은 내부적으로 약한 맥락을 갖고 prop을 통해서 맥락을 주입시켜줄 수 도 있을 것 같고요. 마지막으로 위에서 제시해주신 것과 같이 Context API를 사용할 수 있어 보입니다. 당장 본 글의 케이스에서는 Context API를 꼭 써야할까? 라는 생각이 들 수 있는데 그건 Context API가 props drilling을 해결하기 적절하지 않은 API인 것이 아니라, 조금 더 Context API를 설명하기 적절한 예제가 있다면 좋지 않을까 싶어 의견남깁니다. |
Beta Was this translation helpful? Give feedback.
-
위 문구가 의도한 바는 "코드 상에서 props의 정보가 수정되면, 이를 참조하는 모든 컴포넌트의 코드 수정이 이뤄져야 할 것이다"라고 생각돼요.
다만, "props의 값이 변경됐을 때 이를 사용하는 모든 컴포넌트가 다시 렌더링(변경)된다" 라고 해석될 수 있을 것 같아요.
요즘 다시 리액트 리렌더링은 무조건 피해야 한다는 오해가 다시 생기고 있는 것 같아서 명확한 표현으로 변경되면 좋지 않을까? 생각하게 되었어요.
'개선해보기' 에서
ContextAPI
를 사용하는 것이 추가되는 게 좋을 것 같아요.Composition을 사용했을 때 컴포넌트 구조가 보다 더 flat하게 변경되면서 어느정도 해소되겠지만, 완벽히 해소될 수는 없을 것 같아요. 컴포넌트의 구조를 변경하는 것도 좋겠지만 가장 빠르고 확실한 해결책은
ContextAPI
라고 생각이 돼요.composition 개선 예시 코드에서도 의견을 나누고 싶은데요!
composition 패턴에 익숙하지 않은 분들은 composition에 작성된 전 후 코드 비교를 보고 "별도 컴포넌트를 나눠서 props를 다시 전달하는 것보다 컴포넌트 내용을 다시 적는 게 props 넘기는 절차를 줄여도 되니 더 효과적이구나" 라고 오해할 수도 있을 것 같아요.
아래 코드처럼 별도 컴포넌트를 나누되,
children
을 사용해서 props drilling을 줄이는 예시로 보여주면 어떨까 생각되어요.Beta Was this translation helpful? Give feedback.
All reactions