Skip to content

feat: 04-Tabs 과제 구현 (최병찬)#13

Open
chan-byeong wants to merge 1 commit into
mainfrom
chan-byeong/tabs
Open

feat: 04-Tabs 과제 구현 (최병찬)#13
chan-byeong wants to merge 1 commit into
mainfrom
chan-byeong/tabs

Conversation

@chan-byeong

Copy link
Copy Markdown
Contributor

📝 과제 요약

  • 과제명: tabs 컴포넌트 구현
  • 소요 시간: 40분

💡 설계 및 고민한 부분

AI 없이 스스로 설계하며 가장 신경 쓴 핵심 로직이나 아키텍처(컴포넌트 구조, 상태 관리 등), 혹은 사용자 경험(UX) 개선 사항을 적어주세요.

headless tabs 컴포넌트를 합성 컴포넌트를 활용하여 구현하였습니다.

컴포넌트의 구조나 props는 shadcn의 tabs 컴포넌트를 참고하였습니다.

Tabs
├── TabsList
│   ├── TabsTrigger
│   └── TabsTrigger
├── TabsContent
└── TabsContent

합성 컴포넌트를 통해 사용처에서는 내부 컴포넌트 스타일링에 자유도를 갖고 컴포넌트 구조를 더 쉽게 파악할 수 있습니다.

Tabs 컴포넌트는 활성 탭에 대한 상태를 관리하고 이를 context api를 활용하여 하위 컴포넌트에게 넘겨주게 됩니다.

하위 컴포넌트는 useContext를 통해 활성 탭 정보를 활용하고 있습니다.

기본적인 탭 기능(활성 탭 컨텐츠를 보여줌)만 구현하였습니다.


📖 학습한 내용 및 어려웠던 점 (선택)

문제를 풀며 새롭게 알게 된 개념이나, 구현 중 막혔던 부분이 있다면 공유해 주세요.

  • React v19 부터 Context 자체가 Provider 역할을 하게 된다는 것을 알았습니다. <Context.Provider> 방식이 아닌 <Context> 방식을 통해 provider 컴포넌트를 구현합니다.

❓ 질문 사항 (선택)

라이브 리뷰 때 팀원들과 함께 토론하고 싶거나 의견이 궁금한 부분이 있다면 남겨주세요.


📸 스크린샷 (선택)

UI 관련 과제인 경우 결과 화면 캡처나 GIF를 첨부해 주세요.

@SanginJeong SanginJeong left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Provider 에러를 처리해주시는 점 배웠습니다 고생하셨습니다

onClick={handleClick}
style={{ backgroundColor: `${tabCtx.value === value ? "blue" : ""}` }}
>
{value}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trigger는 value를 text로 바로 사용하는군요. 저는 이 부분도 children을 사용하는 것으로 구현했는데 이부분에 대해서 어떻게 생각하시는지 궁금합니다

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 이 부분에 대해서 궁금합니다.

@chan-byeong chan-byeong Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

두 분의 코드에 관련해서 코멘트 남겼습니다!

요약해서 말쓰드리면 저는 children props로 받게되면 또다른 button이나 a 태그가 기존의 button 컴포넌트 하위로 올 수 있는 경우를 막고자 children 대신 value를 사용하였습니다!

Comment on lines +42 to +46
const tabCtx = useContext(TabContext);

if (!tabCtx) {
throw new Error("tab context must be called in TabsProvier");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

에러처리 부분을 커스텀훅으로 만들어 반복을 줄일 수도 있을 것 같습니다.
Trigger, Content 두 곳에서밖에 사용 하지 않으므로 취향에 따라 갈릴 것 같긴 합니다.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

상인님 말씀처럼 여러 곳(동일 파일 외에도 다른 파일)에서 사용되거나 현재처럼 간단하게 에러를 던지는 로직이 아닌 추가적인 로직 (토스트를 띄운다거나 로깅을 한다거나 등)이 있다면 context를 파싱하는 커스텀 훅을 제작해서 활용하는 편이 좋을 것 같습니다!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type을 명시적으로 import해서 타입과 값을 구분한 점이 인상적이었습니다. 전체적으로 가독성도 좋아 보입니다 👍

onClick={handleClick}
style={{ backgroundColor: `${tabCtx.value === value ? "blue" : ""}` }}
>
{value}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 이 부분에 대해서 궁금합니다.


if (tabCtx.value !== value) return null;

return <div {...props}>{children}</div>;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 별 생각 없이 p 태그를 사용했는데, 의미적으로는 div가 더 적합해 보이네요 👍

@k0nghaa k0nghaa left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

headless 방식으로 구현하셨군요!! 서로 의존성이 없고 재사용성이 높아 좋은 것 같습니다.

return <TabContext value={tabCtx}>{children}</TabContext>;
}

function TabsList({ children, ...props }: { children: ReactNode }) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TabsList와 TabTrigger에서 ...props를 추가한 이유는 사용자가 TabsList에 옵션을 추가할 수 있기 때문 맞을까요?

}) {
const tabCtx = useContext(TabContext);

if (!tabCtx) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

단순 궁금증인데 TabContent와 TabTrigger에 있는 해당 동일 에러 처리를 한 곳에서 처리하는 방법이 있을까요? 🤔

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants