React에서 Props 다루기: Props Drilling, Styled-Component, Redux, Typescript 등 다양한 상황에서 대처하는 전략들

Q&A 큐레이션

1. React에서 props를 무조건 줄이는게 옳을까요?

안녕하세요 React를 기반으로 프로젝트 진행중인 개발자입니다. 리팩토링 작업중 컴포넌트 사이에 예를들어 const {type} = router.query 와 같이 선언으로 가져올수있는부분이나 react-query의 useQuery를 이용해서 가져올수있는 데이터같은경우 각 컴포넌트마다 선언해서 사용하는게 옳은것인지, 부모측에서 선언해서 props로 내려주는게 옳은것인지 궁금한데 직장에 사수가 없어 질문할 곳이 없어 이곳에 질문 남깁니다... 답변부탁드립니다 !


답변

다른 개발자 분들의 의견이 궁금해지는 질문이네요 : ) 제가 이해한 바로는 "props로 자식 컴포넌트에게 react query 응답 데이터를 전달해야할까?" 의 질문으로 이해했습니다. 저의 경우에는 개발시에 데이터를 호출 및 가공처리를 담당하는 컴포넌트와 UI만을 담당하는 컴포넌트를 구분해서 개발하는편입니다. 그 이유는, 대부분의 버그나 이슈는 예측하기 어려운 곳에서 나타나는데요, 데이터를 Api를 이용해 호출해오거나 그 결과를 가공하는 과정이 대부분 해당이 된다고 생각해서에요. 그래서 react query를 쓰더라도 무조건적으로 데이터를 한곳에서 호출 후 자식에게 내려준다는 개념보다는 특정 기능을 하는 페이지를 개발할때 해당 페이지가 어떠한 비즈니스 기능들을 갖고 있는지 구분하고 각 비즈니스별로 Container 라는 컴포넌트를 만들어 해당 파일에서 필요한 데이터를 호출 및 관리하고 있습니다. 공통된 데이터 호출일지라도 react query가 캐싱된 데이터를 가져다가 사용해주기 때문에 중복호출 처리에 대해서는 react query를 믿고 그 역할을 위임하는 편입니다. 이후 각 비즈니스별로 필요한 UI들을 자식컴포넌트로 만들고 각 UI컴포넌트에서 필요로 하는 데이터를 Container에서 내려주고 UI 컴포넌트들은 데이터만 받아서 화면을 구성하도록 개발하고 있습니다. 질문에 대한 답변이 되셨을지 잘 모르겠네요 😅

외 2개 답변 보러 가기

2. props drilling 어떻게 대처하시나요?

변수나 함수를 props로 넘기다 보니 detail 페이지 안에 component들 안으로 넘어가 props.drilling이 생기는데 context api로 하려고 생각중이긴 하지만 이것 또한 불편한점이 조금 있더라구요. 실무에서는 어떻게 하나 궁금합니다


답변

질문주신 내용과 댓글을 확인해 보니 부모의 상태와 연관있는 함수 가령 setState 같은 함수를 프롭스로 전달하고 있는것으로 보여집니다 : ) 이러한 함수를 전달해야하는 깊이가 2뎁스 이상이 될때에는 전역함수로 관리를 하는 편입니다. 보통 위와 같은 경우에 페이지 단위로 전역 스토어를 생성해 관리하거나 특정 컨테이너를 위한 컨텍스트를 생성해 데이터를 관리하는 방법이 있습니다. (제일 좋은건 해당상황을 만들지 않는것이에요, 대부분 위와같은 상황을 자세히 살펴보면 로직적인 수정으로 해결이 가능할때가 많습니다.) 전역 상태 관리를 할때는 전역상태관리 라이브러리 사용을 추천드리는데요, 일부 zustand나 jotai와 같은 전역상태 라이브러리들은 기본적으로 상태 갱신에 따른 re-rendering 문제를 줄여주기 때문입니다. [https://jotai.org/docs/advanced-recipes/large-objects] "대용량 오브젝트나 array 형태의 state에 대해 변경사항이 생겼을 때, 일반적으로 해당 state를 사용하는 모든 컴퍼넌트에 대해서 리렌더링이 발생하는데 그런 문제점을 optics라는 외부 라이브러리를 integration 해서 해결했다." 저는 요즘에는 zustand주로 와 react-query를 사용하고 있습니다 : ) Zustand는 리액트에 의존적이지 않아 데이터가 앱 외부에 저장이 이루어져 여러모로 편리한 도구입니다. 기본적으로 사용을 위한 코드가 짧기 때문에 애용중이에요 ㅎㅎ (하나의 스토어를 사용하기위해 리덕스는 최소2개 이상의 파일을 생성 및 관리해야해요 ㅠㅠ) 만약, 상태변경 함수를 전달하는게 아니라면 부모에서 내려주는 함수에 외부에서 주입되는 지역상태값등의 의존성 값들을 제거해주세요. 프롭스로 받는등 적절히 수정하셔서 별도의 유틸함수로 분리하시면 될것 같습니다. 이후에 분리된 함수를 자식 컴포넌트에서 활용하시면 될것 같아요 : )

외 2개 답변 보러 가기

3. styled-component을 사용할 때 많은 props는 어떻게 해결하시나요?

안녕하세요, 개인 프로젝트를 진행 중에 궁금한 점이 있어 현직의 선배님들께 여쭤보고 싶어 질문을 남깁니다! 현재 React 프로젝트에서 styled-components를 CSS-in-JS로 사용하고 있습니다. 하지만 styled-components를 사용하면서 많아지는 props로 인해 JSX의 복잡도가 높아지는 것 같아 고민이 생겼습니다. 개인 프로젝트에서 사용하고 있는 FlexContainer라는 Flex 스타일(정렬방향, 간격)을 적용하는 컴포넌트입니다. const FlexContainer = styled.div<FlexContainerProps>` display: flex; flex-direction: ${({ col }) => (col ? 'column' : 'row')}; gap: ${({ gap }) => gap && `${gap}rem`}; `; <FlexContainer> 컴포넌트를 '내부 컨텐츠 정렬'을 위해 확장한 <FlexContainerAlign>입니다. const FlexContainerAlign = styled( FlexContainer )<FlexContainerAlignProps>` justify-content: ${({ justifyContent }) => justifyContent}; align-items: ${({ alignItems }) => alignItems}; `; <FlexContainerAlign>을 확장하여 추가적인 style을 적용할 수 있는 <FlexContainerStyle>입니다. const FlexContainerStyle = styled( FlexContainerAlign )<FlexContainerStyleProps>` background-color: ${({ background }) => background && theme.colors.grey}; ${({ styles }) => styles && { ...styles }}; `; FlexContainerStyle 컴포넌트를 사용했을 때 아래처럼 많은 props로 인해 복잡해집니다. <FlexContainerStyle justifyContent="space-between" alignItems="center" background gap={1} styles={{ padding: '1rem 1.5rem', borderRadius: '0.5rem', }}></FlexContainerStyle> 혹시 styled-components를 실무에서 사용하실 때 많은 props를 깔끔하게 정리할 수 있는 팁이 있을까요?


답변

물론, 실제로 styled-component를 사용할 때 많은 소품을 깔끔하게 정리하기 위한 몇 가지 팁이 있습니다. 유틸리티 구성 요소를 사용하십시오. 유틸리티 구성요소는 공통 스타일 세트를 제공하는 구성요소입니다. 예를 들어 다음 스타일을 제공하는 플렉스 컨테이너용 유틸리티 구성 요소를 만들 수 있습니다. display: flex flex-direction: row gap: 1rem 테마를 사용하십시오. 테마는 구성 요소의 스타일을 지정하는 데 사용할 수 있는 미리 정의된 스타일 집합입니다. 예를 들어 다음 스타일을 포함하는 프로젝트의 테마를 만들 수 있습니다. primaryColor: blue secondaryColor: red textColor: black 디자인 시스템을 사용합니다. 디자인 시스템은 일관되고 사용자 친화적인 인터페이스를 구축하는 데 사용할 수 있는 재사용 가능한 구성 요소, 스타일 및 문서의 모음입니다. Material Design 및 Bootstrap과 같이 널리 사용되는 디자인 시스템이 많이 있습니다. 린터를 사용하십시오. Linter는 코드에서 오류를 찾아 수정하는 데 도움이 되는 도구입니다. 많은 linter에는 코드의 가독성과 유지 관리성을 개선하는 데 도움이 되는 규칙이 있습니다. 예를 들어 ESLint 린터에는 긴 코드 줄을 사용하지 않도록 도와주는 규칙이 있습니다. 일관된 명명 규칙을 사용하십시오. 일관된 명명 규칙을 사용하면 코드를 더 읽기 쉽고 유지 관리할 수 있습니다. 예를 들어 소품에 다음 명명 규칙을 사용할 수 있습니다. camelCase구성 요소에 전달되는 소품의 경우 kebab-case구성 요소의 스타일을 지정하는 데 사용되는 소품의 경우 주석을 사용하십시오. 주석은 코드가 수행하는 작업을 설명하는 데 도움이 될 수 있습니다. 예를 들어 특정 소품의 목적을 설명하는 주석을 추가할 수 있습니다. 코드를 더 작은 파일로 나눕니다. 큰 파일은 읽고 유지 관리하기 어려울 수 있습니다. 각 구성 요소 또는 관련 구성 요소 그룹에 대해 별도의 파일을 만들어 코드를 더 작은 파일로 나눌 수 있습니다. 코드 탐색 및 리팩터링 기능이 있는 코드 편집기를 사용합니다. 코드 탐색 및 리팩터링 기능이 있는 코드 편집기를 사용하면 코드를 보다 빠르고 쉽게 변경할 수 있습니다. 예를 들어 변수 또는 함수의 정의로 빠르게 이동할 수 있는 기능이 있는 코드 편집기를 사용할 수 있습니다. 디버거를 사용하십시오. 디버거는 코드를 한 줄씩 단계별로 실행하고 변수 값을 검사하는 데 도움이 될 수 있습니다. 이는 코드의 문제를 디버그하려고 할 때 유용할 수 있습니다. 라고 bard가 대답했습니다.

외 2개 답변 보러 가기

4. 리엑트 props 전달 뎁스는 어느정도가 적당할까요?

props를 전달하는 뎁스에 대한 가이드라인이나 어느 정도의 뎁스가 성능적으로 좋은지 판단하기가 어렵습니다. 리엑트로 개발하시는 분들은 어떤 기준으로 props 뎁스를 전달하고 계신가요? global state로 전환하는 기준도 궁금합니다. 감사합니다!


답변

절대적인 기준은 없습니다. props를 통해서 부모에서 자식으로 내려가는 값들은 의존성을 가지게 되고 그 props가 여러 컴포넌트에 계속 타고 타고 내려가게 된다면(props drilling 이라고 합니다) 예상치 못한 side effect가 발생하기도 쉽고, 변화에 유연하게 대응하기도 어렵습니다. 저는 사용하게되면 한 번 정도만 props로 사용하고, 두 번 이상 사용해야 하는 경우라면 차라리 context로 분리합니다. 이는 기준이 사람마다 다르므로 정답은 없는 것 같아요.

외 1개 답변 보러 가기

5. redux에서 child에게 props를 전달 vs useSelector사용 중 어떤 방법을 사용하나요?

리덕스를 쓴다고 가정하고 상위 컴포넌트인 a컴포넌트 하위 컴포넌트인 b컴포넌트에서 동시에 사용되는 state가 있습니다. 이럴경우 a에서 useSelector로 불러온후 b에 props로 전달하나요 아니면 b에서도 useSelector로 불러와서 사용하나요?


답변

저라면 useSelector로 가져올것 같습니다 props에 일일히 추가하는거와 타입스크립트라면 props 에 타입 지정한게 있다면 거기에도 추가해줘야하고 좀 번거로울것 같아서요

외 1개 답변 보러 가기

6. Typescript에서 as 는 왜 안 좋은가요?

오늘 회사에서 코드리뷰를 받았어요. 회사에서는 typescript를 사용합니다. typescript를 처음 써보니까 어렵네요. props의 depth가 너무 깊어서 type을 추론하기가 어려워서 any를 사용하거나 as를 사용해서 코드를 짰습니다. 이 부분에서 코드리뷰에서 받은 코멘트가 as나 any는 좋지 않다라는 의견을 받았네요. 개발자 선배분들은 어떤 점에서 as가 안 좋다고 생각하시나요? 그리고 좋은 수정방법이 있을까요?


답변

1. as는 타입스크립트의 타입 검사 기능을 포기하겠다는 것과 마찬가지 입니다 2. as이후로 타입 불일치 또는 프로퍼티 불일치가 발생해도 컴파일 타임에(또는 IDE에서 실시간으로) 에러를 체킹할 수 없습니다. 더 이상 타입스크립트 컴파일러가 책임지지 않습니다 3. 그러므로 as는 (사용 여부에 따라서) 런타임 에러가 발생할 가능성을 높여줍니다 4. 타입스크립트를 사용하는 주된 이유는 런타임 에러를 컴파일 타임으로 당겨와서 에러를 빨리 수정하자는 것인데 사용 취지에 어긋나는 일이라고 할 수 있겠습니다 5. as를 사용해도 되는 상황은 타입이 확정적인 상황이고 다른 타입이 올 가능성이 없는 상황에 사용할 수는 있겠습니다 6. 서버에서 데이터를 응답받을 때는 zod등의 런타임 타입 체킹 라이브러리를 사용하면 as 를 사용하지 않아도 됩니다 7. 타입이 unknown인 경우도 마찬가지로 런타임 타입 체킹 라이브러리를 사용하면 as 를 사용하지 않아도 됩니다 8. 위의 내용들은 as를 사용하여 몇번 골머리를 겪다보면 저절로 체득하게 됩니다 9. 말이 아닌 몸으로 깨닫고 싶으시면 집에 가셔서 토이 프로젝트를 만드신 후에 모든 타입을 as로 도배해 보세요

외 3개 답변 보러 가기

지금 가입하면 모든 질문의 답변을 볼 수 있어요!

현직자들의 명쾌한 답변을 얻을 수 있어요.

또는

이미 회원이신가요?

실무, 커리어 고민이 있다면

새로운 질문 올리기

지금 가입하면 모든 질문의 답변을 볼 수 있어요!