Conversation
Walkthrough새로운 Table UI 컴포넌트 세트( Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Dev as 스토리북 사용자
participant SB as Storybook
participant Story as Basic Story
participant UI as Table 컴포넌트군
Dev->>SB: Basic 스토리 선택
SB->>Story: render()
Story->>UI: Compose: <Table> -> <TableHeader/> + <TableBody/>
UI->>UI: TableHeader -> TableRow -> TableHead (헤더 렌더)
UI->>UI: TableBody -> TableRow* -> TableCell* (데이터 렌더)
UI-->>SB: DOM 반환
SB-->>Dev: 미리보기 표시
note right of UI: 각 컴포넌트는 props 전달 및 클래스 병합만 수행
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 추가로 주의할 파일/영역:
Suggested reviewers
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro 📒 Files selected for processing (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
🔇 Additional comments (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Update: 2025년 11월 17일 14시 36분 50초 |
There was a problem hiding this comment.
Actionable comments posted: 5
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (6)
src/shared/ui/Table/Table.stories.tsx(1 hunks)src/shared/ui/Table/Table.tsx(1 hunks)src/shared/ui/Table/TableBody.tsx(1 hunks)src/shared/ui/Table/TableHead.tsx(1 hunks)src/shared/ui/Table/index.ts(1 hunks)src/shared/ui/Table/types.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
src/shared/ui/Table/TableBody.tsx (1)
src/shared/ui/Table/types.ts (1)
Column(3-7)
src/shared/ui/Table/TableHead.tsx (1)
src/shared/ui/Table/types.ts (1)
Column(3-7)
src/shared/ui/Table/Table.tsx (4)
src/shared/ui/Table/types.ts (1)
Column(3-7)src/shared/ui/Table/index.ts (1)
Table(1-1)src/shared/ui/Table/TableHead.tsx (1)
TableHead(10-20)src/shared/ui/Table/TableBody.tsx (1)
TableBody(11-37)
src/shared/ui/Table/Table.stories.tsx (2)
src/shared/ui/Table/Table.tsx (1)
Table(14-31)src/shared/ui/Table/types.ts (1)
Column(3-7)
🔇 Additional comments (4)
src/shared/ui/Table/index.ts (1)
1-1: 깔끔한 배럴 익스포트 구현입니다.표준적인 모듈 재export 패턴을 따르고 있습니다.
src/shared/ui/Table/types.ts (1)
3-7: 타입 정의가 올바르게 구현되었습니다.제네릭 타입 제약과 optional render 함수가 적절하게 정의되어 있습니다.
src/shared/ui/Table/TableHead.tsx (1)
10-20: 헤더 컴포넌트가 올바르게 구현되었습니다.sticky 포지셔닝과 key 생성 로직이 적절합니다.
src/shared/ui/Table/Table.tsx (1)
14-31: Table 컴포넌트가 깔끔하게 구현되었습니다.TableHead와 TableBody를 적절하게 조합하고 있으며, hideHead prop을 통한 조건부 렌더링이 올바릅니다.
src/shared/ui/Table/TableBody.tsx
Outdated
| {data.map((row, rIdx) => ( | ||
| <Flex key={rIdx} className="items-center gap-4 border-b border-gray-200 px-4 py-2"> |
There was a problem hiding this comment.
행 키로 배열 인덱스 사용 시 주의가 필요합니다.
현재 rIdx를 키로 사용하고 있는데, 데이터 배열의 순서가 변경되거나 항목이 추가/삭제될 경우 React의 렌더링 최적화가 제대로 동작하지 않을 수 있습니다. 가능하다면 각 행 데이터에서 고유 식별자(예: id)를 추출하여 키로 사용하는 것을 권장합니다.
다음과 같이 개선할 수 있습니다:
- {data.map((row, rIdx) => (
- <Flex key={rIdx} className="items-center gap-4 border-b border-gray-200 px-4 py-2">
+ {data.map((row, rIdx) => {
+ // row에 id 같은 고유 속성이 있다면 사용, 없으면 index 폴백
+ const rowKey = 'id' in row ? String(row.id) : rIdx;
+ return (
+ <Flex key={rowKey} className="items-center gap-4 border-b border-gray-200 px-4 py-2">또는 Props에 getRowKey?: (row: T, index: number) => string | number 같은 prop을 추가하여 사용자가 키 생성 방식을 제어할 수 있도록 할 수 있습니다.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {data.map((row, rIdx) => ( | |
| <Flex key={rIdx} className="items-center gap-4 border-b border-gray-200 px-4 py-2"> | |
| {data.map((row, rIdx) => { | |
| // row에 id 같은 고유 속성이 있다면 사용, 없으면 index 폴백 | |
| const rowKey = 'id' in row ? String(row.id) : rIdx; | |
| return ( | |
| <Flex key={rowKey} className="items-center gap-4 border-b border-gray-200 px-4 py-2"> |
🤖 Prompt for AI Agents
In src/shared/ui/Table/TableBody.tsx around lines 18 to 19, the code uses the
array index (rIdx) as the React key which can break rendering when rows are
reordered/added/removed; change the component to derive a stable key from the
row (e.g., row.id or another unique field) and fallback only if absent, or add a
getRowKey?: (row: T, index: number) => string | number prop so callers can
supply a stable key generator; update the map to call getRowKey(row, rIdx) or
use row.id (or a configured unique property) instead of rIdx and ensure the prop
type and default fallback are added to the component props.
src/shared/ui/Table/TableBody.tsx
Outdated
| {columns.map((col, cIdx) => { | ||
| const value = row[col.key]; | ||
| const content = col.render ? col.render(value, row) : (value as React.ReactNode); | ||
| return ( | ||
| <Body3 | ||
| key={cIdx} |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
열 키를 개선할 수 있습니다.
현재 cIdx를 열 키로 사용하고 있습니다. 열 순서는 일반적으로 변경되지 않으므로 큰 문제는 아니지만, col.key를 사용하면 더 명시적이고 안정적입니다.
- key={cIdx}
+ key={String(col.key)}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {columns.map((col, cIdx) => { | |
| const value = row[col.key]; | |
| const content = col.render ? col.render(value, row) : (value as React.ReactNode); | |
| return ( | |
| <Body3 | |
| key={cIdx} | |
| {columns.map((col, cIdx) => { | |
| const value = row[col.key]; | |
| const content = col.render ? col.render(value, row) : (value as React.ReactNode); | |
| return ( | |
| <Body3 | |
| key={String(col.key)} |
🤖 Prompt for AI Agents
In src/shared/ui/Table/TableBody.tsx around lines 20 to 25, the column elements
use cIdx as the React key which is less explicit; change the key to use col.key
(or `${col.key}-${cIdx}` as a safe fallback) so keys are stable and meaningful;
ensure col.key is a string/unique identifier and fall back to the index only if
col.key is undefined to avoid warnings.
src/shared/ui/Table/TableBody.tsx
Outdated
| <Flex key={rIdx} className="items-center gap-4 border-b border-gray-200 px-4 py-2"> | ||
| {columns.map((col, cIdx) => { | ||
| const value = row[col.key]; | ||
| const content = col.render ? col.render(value, row) : (value as React.ReactNode); |
There was a problem hiding this comment.
타입 단언의 안전성을 검토해주세요.
value를 React.ReactNode로 단언하고 있지만, 실제로 모든 타입의 값이 유효한 ReactNode는 아닙니다. 예를 들어 객체, 함수, Symbol 등은 렌더링 시 에러를 발생시킬 수 있습니다.
다음과 같이 개선할 수 있습니다:
- const content = col.render ? col.render(value, row) : (value as React.ReactNode);
+ const content = col.render
+ ? col.render(value, row)
+ : (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' || value === null || value === undefined)
+ ? value
+ : String(value);또는 Column 타입 정의에서 render가 없을 때는 value가 기본적으로 렌더링 가능한 타입이어야 한다는 제약을 추가할 수 있습니다.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const content = col.render ? col.render(value, row) : (value as React.ReactNode); | |
| // Before: | |
| // const content = col.render ? col.render(value, row) : (value as React.ReactNode); | |
| // After: | |
| const content = col.render | |
| ? col.render(value, row) | |
| : (typeof value === 'string' | |
| || typeof value === 'number' | |
| || typeof value === 'boolean' | |
| || value === null | |
| || value === undefined) | |
| ? value | |
| : String(value); |
🤖 Prompt for AI Agents
In src/shared/ui/Table/TableBody.tsx around line 22, the code unsafely asserts
value as React.ReactNode when col.render is absent; validate and handle
non-renderable types instead of blind assertion. Update logic to detect
renderable primitives/React elements (string, number, boolean, null, undefined,
React.isValidElement) and return them directly; for objects/functions/symbols
either call a safe formatter (e.g., JSON.stringify with try/catch or a toString
fallback) or render a placeholder; alternatively tighten the Column type to
require a render function when the value type is not guaranteed to be renderable
so TypeScript enforces safe usage.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/shared/ui/Table/Table.stories.tsx (1)
44-117: 데이터 중복이 여전히 존재합니다.
- Lines 81-86과 100-104가 동일합니다
- Lines 87-92와 105-110이 동일합니다
- Lines 93-98과 111-116이 동일합니다
스크롤 테스트를 위한 의도적인 중복이라면 문제없지만, 실수라면 중복 항목을 제거해 주세요.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
src/shared/ui/Table/Table.stories.tsx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/shared/ui/Table/Table.stories.tsx (2)
src/shared/ui/Table/Table.tsx (1)
Table(14-31)src/shared/ui/Table/types.ts (1)
Column(3-7)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: preview-storybook
🔇 Additional comments (1)
src/shared/ui/Table/Table.stories.tsx (1)
133-139: 이전 리뷰의 hideHead 누락 이슈가 해결되었습니다.
NoHeader스토리에hideHead: trueprop이 올바르게 추가되어 헤더 없는 테이블이 정상적으로 렌더링됩니다.
There was a problem hiding this comment.
Actionable comments posted: 4
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (9)
src/shared/index.ts(1 hunks)src/shared/ui/Table/Table.stories.tsx(1 hunks)src/shared/ui/Table/Table.tsx(1 hunks)src/shared/ui/Table/TableBody.tsx(1 hunks)src/shared/ui/Table/TableCell.tsx(1 hunks)src/shared/ui/Table/TableHead.tsx(1 hunks)src/shared/ui/Table/TableHeader.tsx(1 hunks)src/shared/ui/Table/TableRow.tsx(1 hunks)src/shared/ui/Table/index.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (7)
src/shared/ui/Table/TableHeader.tsx (7)
src/shared/ui/Table/Table.tsx (1)
Props(5-15)src/shared/ui/Table/TableBody.tsx (1)
Props(5-8)src/shared/ui/Table/TableCell.tsx (1)
Props(7-10)src/shared/ui/Table/TableHead.tsx (1)
Props(7-10)src/shared/ui/Table/TableRow.tsx (1)
Props(5-8)src/shared/index.ts (2)
TableHeader(25-25)cn(30-30)src/shared/ui/Table/index.ts (1)
TableHeader(2-2)
src/shared/ui/Table/TableRow.tsx (7)
src/shared/ui/Table/Table.tsx (1)
Props(5-15)src/shared/ui/Table/TableBody.tsx (1)
Props(5-8)src/shared/ui/Table/TableCell.tsx (1)
Props(7-10)src/shared/ui/Table/TableHead.tsx (1)
Props(7-10)src/shared/ui/Table/TableHeader.tsx (1)
Props(5-8)src/shared/index.ts (2)
TableRow(25-25)cn(30-30)src/shared/ui/Table/index.ts (1)
TableRow(4-4)
src/shared/ui/Table/TableBody.tsx (7)
src/shared/ui/Table/Table.tsx (1)
Props(5-15)src/shared/ui/Table/TableCell.tsx (1)
Props(7-10)src/shared/ui/Table/TableHead.tsx (1)
Props(7-10)src/shared/ui/Table/TableHeader.tsx (1)
Props(5-8)src/shared/ui/Table/TableRow.tsx (1)
Props(5-8)src/shared/index.ts (2)
TableBody(25-25)cn(30-30)src/shared/ui/Table/index.ts (1)
TableBody(3-3)
src/shared/ui/Table/TableHead.tsx (7)
src/shared/ui/Table/Table.tsx (1)
Props(5-15)src/shared/ui/Table/TableBody.tsx (1)
Props(5-8)src/shared/ui/Table/TableCell.tsx (1)
Props(7-10)src/shared/ui/Table/TableHeader.tsx (1)
Props(5-8)src/shared/ui/Table/TableRow.tsx (1)
Props(5-8)src/shared/index.ts (3)
TableHead(25-25)cn(30-30)Body2(24-24)src/shared/ui/Table/index.ts (1)
TableHead(5-5)
src/shared/ui/Table/TableCell.tsx (7)
src/shared/ui/Table/Table.tsx (1)
Props(5-15)src/shared/ui/Table/TableBody.tsx (1)
Props(5-8)src/shared/ui/Table/TableHead.tsx (1)
Props(7-10)src/shared/ui/Table/TableHeader.tsx (1)
Props(5-8)src/shared/ui/Table/TableRow.tsx (1)
Props(5-8)src/shared/index.ts (3)
TableCell(25-25)cn(30-30)Body2(24-24)src/shared/ui/Table/index.ts (1)
TableCell(6-6)
src/shared/ui/Table/Table.stories.tsx (8)
src/shared/index.ts (6)
Table(25-25)TableHeader(25-25)TableRow(25-25)TableHead(25-25)TableBody(25-25)TableCell(25-25)src/shared/ui/Table/Table.tsx (1)
Table(16-26)src/shared/ui/Table/index.ts (6)
Table(1-1)TableHeader(2-2)TableRow(4-4)TableHead(5-5)TableBody(3-3)TableCell(6-6)src/shared/ui/Table/TableHeader.tsx (1)
TableHeader(10-16)src/shared/ui/Table/TableRow.tsx (1)
TableRow(10-16)src/shared/ui/Table/TableHead.tsx (1)
TableHead(12-21)src/shared/ui/Table/TableBody.tsx (1)
TableBody(10-16)src/shared/ui/Table/TableCell.tsx (1)
TableCell(12-20)
src/shared/ui/Table/Table.tsx (7)
src/shared/ui/Table/TableBody.tsx (1)
Props(5-8)src/shared/ui/Table/TableCell.tsx (1)
Props(7-10)src/shared/ui/Table/TableHead.tsx (1)
Props(7-10)src/shared/ui/Table/TableHeader.tsx (1)
Props(5-8)src/shared/ui/Table/TableRow.tsx (1)
Props(5-8)src/shared/index.ts (2)
Table(25-25)cn(30-30)src/shared/ui/Table/index.ts (1)
Table(1-1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: preview-storybook
🔇 Additional comments (9)
src/shared/ui/Table/TableCell.tsx (1)
15-15: 텍스트 색상이 너무 연해 가독성이 떨어질 수 있습니다.
text-gray-400은 상당히 밝은 색상으로, 일반 텍스트 콘텐츠에 사용하기에는 대비가 부족할 수 있습니다. 접근성 가이드라인(WCAG)에서는 일반 텍스트에 대해 최소 4.5:1의 명암비를 권장합니다.
text-gray-600이상의 더 어두운 색상을 사용하는 것을 고려해주세요:- <Body2 className="whitespace-pre-wrap text-gray-400" weight="normal"> + <Body2 className="whitespace-pre-wrap text-gray-600" weight="normal">src/shared/ui/Table/TableHead.tsx (1)
12-20: LGTM!헤더 셀 구현이 적절합니다.
text-gray-700을 사용하여 헤더와 데이터 셀을 시각적으로 구분하고,whitespace-nowrap으로 헤더 텍스트가 줄바꿈되지 않도록 처리한 것이 좋습니다.src/shared/index.ts (1)
25-25: LGTM!모든 Table 컴포넌트가 올바르게 export되었습니다.
src/shared/ui/Table/Table.tsx (2)
21-21:table-fixed레이아웃으로 인한 콘텐츠 오버플로우를 검토해주세요.
table-fixed를 사용하면 모든 열이 동일한 너비를 가지게 되어, 콘텐츠 길이가 불균등할 경우 텍스트가 잘리거나 보기 불편할 수 있습니다. 현재 조회용으로만 사용된다고 하셨지만, 향후 다양한 데이터 형식에 대응하기 어려울 수 있습니다.다음을 확인해주세요:
- 실제 사용 시나리오에서 모든 열의 콘텐츠 길이가 비슷한지
- 긴 텍스트가 있을 경우
whitespace-pre-wrap이나 말줄임 처리가 적절히 동작하는지필요하다면
table-auto로 변경하거나, Props에layout?: 'auto' | 'fixed'를 추가하여 상황에 맞게 선택할 수 있도록 하는 것을 고려해주세요.
19-19:no-scrollbar유틸리티 클래스 정의 확인 완료
src/index.css에서.no-scrollbar가 정의되어 있음을 확인했습니다.src/shared/ui/Table/TableHeader.tsx (1)
10-15: LGTM!테이블 헤더 영역을 깔끔하게 구분하는 간단하고 효과적인 구현입니다.
src/shared/ui/Table/TableRow.tsx (1)
10-15: LGTM!행 사이의 구분선을 적절하게 처리하고,
last:border-0으로 마지막 행의 불필요한 테두리를 제거한 깔끔한 구현입니다.src/shared/ui/Table/index.ts (1)
1-6: LGTM!모든 Table 컴포넌트가 올바르게 export되었으며, 논리적인 계층 구조 순서를 따르고 있습니다.
src/shared/ui/Table/TableBody.tsx (1)
10-15: LGTM!테이블 본문 영역을 감싸는 간단하고 명확한 구현입니다.
bg-white를 사용하여 헤더(bg-gray-50)와 시각적으로 구분되도록 했습니다.참고: 이전 리뷰 코멘트들은 데이터 렌더링 로직이 포함된 다른 버전에 대한 것으로, 현재의 단순한 래퍼 컴포넌트 구현과는 관련이 없습니다.
| export const Basic: StoryObj<typeof PrimitiveMeta> = { | ||
| render: () => ( | ||
| <Table> | ||
| <TableHeader> | ||
| <TableRow> | ||
| <TableHead>날짜</TableHead> | ||
| <TableHead>카테고리</TableHead> | ||
| <TableHead>점수</TableHead> | ||
| </TableRow> | ||
| </TableHeader> | ||
| <TableBody> | ||
| {data.map((row, i) => ( | ||
| <TableRow key={i}> | ||
| <TableCell>{row.createdAt}</TableCell> | ||
| <TableCell>{row.scoreCategory}</TableCell> | ||
| <TableCell>{row.amount.toFixed(3)}점</TableCell> | ||
| </TableRow> | ||
| ))} | ||
| </TableBody> | ||
| </Table> | ||
| ), | ||
| }; |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
스토리를 더 인터랙티브하게 만들 수 있습니다.
현재 Basic 스토리는 render 함수에 데이터가 하드코딩되어 있어 Storybook의 Controls 패널을 통해 수정할 수 없습니다. 데이터를 args로 받도록 하면 사용자가 다양한 데이터 조합을 테스트할 수 있습니다.
다음과 같이 개선할 수 있습니다:
+type StoryArgs = {
+ data: typeof data;
+};
+
-export const Basic: StoryObj<typeof PrimitiveMeta> = {
+export const Basic: StoryObj<StoryArgs> = {
+ args: {
+ data,
+ },
- render: () => (
+ render: ({ data }) => (
<Table>
<TableHeader>
<TableRow>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export const Basic: StoryObj<typeof PrimitiveMeta> = { | |
| render: () => ( | |
| <Table> | |
| <TableHeader> | |
| <TableRow> | |
| <TableHead>날짜</TableHead> | |
| <TableHead>카테고리</TableHead> | |
| <TableHead>점수</TableHead> | |
| </TableRow> | |
| </TableHeader> | |
| <TableBody> | |
| {data.map((row, i) => ( | |
| <TableRow key={i}> | |
| <TableCell>{row.createdAt}</TableCell> | |
| <TableCell>{row.scoreCategory}</TableCell> | |
| <TableCell>{row.amount.toFixed(3)}점</TableCell> | |
| </TableRow> | |
| ))} | |
| </TableBody> | |
| </Table> | |
| ), | |
| }; | |
| type StoryArgs = { | |
| data: typeof data; | |
| }; | |
| export const Basic: StoryObj<StoryArgs> = { | |
| args: { | |
| data, | |
| }, | |
| render: ({ data }) => ( | |
| <Table> | |
| <TableHeader> | |
| <TableRow> | |
| <TableHead>날짜</TableHead> | |
| <TableHead>카테고리</TableHead> | |
| <TableHead>점수</TableHead> | |
| </TableRow> | |
| </TableHeader> | |
| <TableBody> | |
| {data.map((row, i) => ( | |
| <TableRow key={i}> | |
| <TableCell>{row.createdAt}</TableCell> | |
| <TableCell>{row.scoreCategory}</TableCell> | |
| <TableCell>{row.amount.toFixed(3)}점</TableCell> | |
| </TableRow> | |
| ))} | |
| </TableBody> | |
| </Table> | |
| ), | |
| }; |
🤖 Prompt for AI Agents
In src/shared/ui/Table/Table.stories.tsx around lines 52-73, the Basic story
uses hardcoded data inside render which prevents Storybook Controls from
modifying it; refactor the story to accept args (e.g., render: (args) => ...)
and use args.data (with a sensible default via Basic.args) for the rows so users
can edit the dataset from Controls; update the StoryObj generic if needed to
reflect the arg type and add Basic.args = { data: [...] } providing the original
sample so backwards compatibility is preserved.
| </TableHeader> | ||
| <TableBody> | ||
| {data.map((row, i) => ( | ||
| <TableRow key={i}> |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
배열 인덱스를 key로 사용하고 있습니다.
정적 데모 데이터의 경우 허용되지만, 안정적인 고유 식별자를 key로 사용하는 것이 더 좋은 관행입니다. 예를 들어, createdAt과 scoreCategory를 조합하여 사용할 수 있습니다.
- {data.map((row, i) => (
- <TableRow key={i}>
+ {data.map((row) => (
+ <TableRow key={`${row.createdAt}-${row.scoreCategory}`}>🤖 Prompt for AI Agents
In src/shared/ui/Table/Table.stories.tsx around line 64, the story currently
uses the array index as the React key which can cause unstable identity; replace
the index with a stable unique key built from the row data (e.g., combine
createdAt and scoreCategory into a single string) and ensure it’s deterministic
(stringify or format timestamps) and falls back to a safe unique value if either
field is missing.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
src/shared/ui/Table/TableCell.tsx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/shared/ui/Table/TableCell.tsx (7)
src/shared/ui/Table/Table.tsx (1)
Props(5-15)src/shared/ui/Table/TableBody.tsx (1)
Props(5-8)src/shared/ui/Table/TableHead.tsx (1)
Props(7-10)src/shared/ui/Table/TableHeader.tsx (1)
Props(5-8)src/shared/ui/Table/TableRow.tsx (1)
Props(5-8)src/shared/index.ts (3)
TableCell(25-25)cn(30-30)Body2(24-24)src/shared/ui/Table/index.ts (1)
TableCell(6-6)
🔇 Additional comments (1)
src/shared/ui/Table/TableCell.tsx (1)
1-10: Props 타입 정의와 import가 적절합니다.타입 정의가 다른 Table 컴포넌트들과 일관성 있게 구현되어 있고, 필요한 import만 포함하고 있습니다.
| export function TableCell({ className, children, ...props }: Props) { | ||
| return ( | ||
| <td className={cn('px-4 py-2 align-middle md:px-4', className)} {...props}> | ||
| <Body2 className="whitespace-pre-wrap text-gray-400" weight="normal"> | ||
| {children} | ||
| </Body2> | ||
| </td> | ||
| ); | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
중복된 md:px-4 클래스를 제거하세요.
px-4는 모든 화면 크기에 이미 적용되므로, md:px-4는 중복됩니다. Tailwind의 mobile-first 접근 방식에서 기본 클래스는 모든 브레이크포인트에 적용되며, md: 접두사는 해당 브레이크포인트 이상에서 값을 재정의할 때만 의미가 있습니다.
참고: Body2에서 패딩을 제거하여 이전 리뷰의 중복 패딩 문제가 해결된 점은 좋습니다.
다음과 같이 수정하여 중복을 제거하세요:
- <td className={cn('px-4 py-2 align-middle md:px-4', className)} {...props}>
+ <td className={cn('px-4 py-2 align-middle', className)} {...props}>만약 모바일과 데스크톱에서 다른 패딩을 의도했다면, 다음과 같은 패턴을 사용하세요:
- <td className={cn('px-4 py-2 align-middle md:px-4', className)} {...props}>
+ <td className={cn('px-2 py-2 align-middle md:px-4', className)} {...props}>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export function TableCell({ className, children, ...props }: Props) { | |
| return ( | |
| <td className={cn('px-4 py-2 align-middle md:px-4', className)} {...props}> | |
| <Body2 className="whitespace-pre-wrap text-gray-400" weight="normal"> | |
| {children} | |
| </Body2> | |
| </td> | |
| ); | |
| } | |
| export function TableCell({ className, children, ...props }: Props) { | |
| return ( | |
| <td className={cn('px-4 py-2 align-middle', className)} {...props}> | |
| <Body2 className="whitespace-pre-wrap text-gray-400" weight="normal"> | |
| {children} | |
| </Body2> | |
| </td> | |
| ); | |
| } |
🤖 Prompt for AI Agents
In src/shared/ui/Table/TableCell.tsx around lines 12 to 20, remove the redundant
Tailwind class `md:px-4` from the td class list because `px-4` already applies
to all breakpoints; update the class string to only include `px-4 py-2
align-middle` (plus the incoming className) so you don't duplicate padding; if
you actually intended different padding on md and up, replace `md:px-4` with the
desired `md:px-{value}` instead of duplicating the same value.
🔥 연관 이슈
🚀 작업 내용
🤔 고민했던 내용
Table, TableBody, TableCell, TableHead, TableHeader, TableRow를 조합하여 사용할 수 있도록 하였습니다💬 리뷰 중점사항
Summary by CodeRabbit