fix: 게시판 3화면이 서버에서 클라이언트 함수를 부르던 문제
`board-post-columns.tsx`가 `'use client'` 모듈인데 서버 컴포넌트인 page가 거기 함수를 직접
호출했다 — 클라이언트 모듈의 non-component export는 서버에서 참조 프록시라 부르면 던진다
("Attempted to call faqColumns() from the server"). 공지·FAQ·1:1문의 세 화면이 모두 같았다.
컬럼을 클라이언트에서 만들도록 옮겼다. `boardPostColumns(boardType, page, pageSize)` 하나가
세 팩토리를 갈라 주고, `BoardPostList`가 이미 받고 있던 boardType·currentPage·pageSize로 직접
부른다. page는 columns prop을 넘기지 않는다.
옮기지 않고 `'use client'`만 떼는 방법은 안 된다 — 컬럼의 `render`가 함수라 서버에서 만들어
클라이언트로 넘기는 것 자체가 RSC 경계를 못 넘는다. 만드는 쪽을 클라이언트로 옮겨야 한다.
확인: FAQ 목록을 클라이언트에서 렌더해 컬럼 8개(번호·구분·유형·제목·작성자·등록일·사용여부·
관리)가 서고 콘솔 오류가 없다.
Co-Authored-By: Claude Opus 5
@298786b12a10a692f217114c3c06503ff7c17665
--- app/(protected)/(basic)/boards/_components/board-post-columns.tsx
+++ app/(protected)/(basic)/boards/_components/board-post-columns.tsx
... | ... | @@ -54,7 +54,7 @@ |
| 54 | 54 |
}; |
| 55 | 55 |
} |
| 56 | 56 |
|
| 57 |
-export function noticeColumns(page: number, pageSize: number): FoxListColumn<BoardPost>[] {
|
|
| 57 |
+function noticeColumns(page: number, pageSize: number): FoxListColumn<BoardPost>[] {
|
|
| 58 | 58 |
return [ |
| 59 | 59 |
numberColumn(page, pageSize), |
| 60 | 60 |
{
|
... | ... | @@ -99,7 +99,7 @@ |
| 99 | 99 |
]; |
| 100 | 100 |
} |
| 101 | 101 |
|
| 102 |
-export function faqColumns(page: number, pageSize: number): FoxListColumn<BoardPost>[] {
|
|
| 102 |
+function faqColumns(page: number, pageSize: number): FoxListColumn<BoardPost>[] {
|
|
| 103 | 103 |
return [ |
| 104 | 104 |
numberColumn(page, pageSize), |
| 105 | 105 |
{
|
... | ... | @@ -136,7 +136,7 @@ |
| 136 | 136 |
]; |
| 137 | 137 |
} |
| 138 | 138 |
|
| 139 |
-export function inquiryColumns(page: number, pageSize: number): FoxListColumn<BoardPost>[] {
|
|
| 139 |
+function inquiryColumns(page: number, pageSize: number): FoxListColumn<BoardPost>[] {
|
|
| 140 | 140 |
return [ |
| 141 | 141 |
numberColumn(page, pageSize), |
| 142 | 142 |
{
|
... | ... | @@ -184,3 +184,13 @@ |
| 184 | 184 |
actionsColumn('inquiry'),
|
| 185 | 185 |
]; |
| 186 | 186 |
} |
| 187 |
+ |
|
| 188 |
+export function boardPostColumns( |
|
| 189 |
+ boardType: BoardType, |
|
| 190 |
+ page: number, |
|
| 191 |
+ pageSize: number |
|
| 192 |
+): FoxListColumn<BoardPost>[] {
|
|
| 193 |
+ if (boardType === 'notice') return noticeColumns(page, pageSize); |
|
| 194 |
+ if (boardType === 'faq') return faqColumns(page, pageSize); |
|
| 195 |
+ return inquiryColumns(page, pageSize); |
|
| 196 |
+} |
--- app/(protected)/(basic)/boards/_components/board-post-list.tsx
+++ app/(protected)/(basic)/boards/_components/board-post-list.tsx
... | ... | @@ -4,10 +4,7 @@ |
| 4 | 4 |
import { useState, useTransition, type ReactNode } from 'react';
|
| 5 | 5 |
import { FoxButton } from '@fox/core/components/fox-button';
|
| 6 | 6 |
import { FoxIconButton } from '@fox/core/components/fox-icon-button';
|
| 7 |
-import {
|
|
| 8 |
- FoxListContainer, |
|
| 9 |
- type FoxListColumn, |
|
| 10 |
-} from '@fox/core/components/fox-list-container'; |
|
| 7 |
+import { FoxListContainer } from '@fox/core/components/fox-list-container';
|
|
| 11 | 8 |
import { FoxSelectText } from '@fox/core/components/fox-select-text';
|
| 12 | 9 |
import { FoxTab } from '@fox/core/components/fox-tab';
|
| 13 | 10 |
import { FoxTabItem } from '@fox/core/components/fox-tab-item';
|
... | ... | @@ -24,12 +21,12 @@ |
| 24 | 21 |
} from '@/lib/domain/board-post-query'; |
| 25 | 22 |
import { BoardPostFormModal } from './board-post-form-modal';
|
| 26 | 23 |
import styles from './board-post-list.module.scss'; |
| 24 |
+import { boardPostColumns } from './board-post-columns';
|
|
| 27 | 25 |
|
| 28 | 26 |
interface BoardPostListProps {
|
| 29 | 27 |
boardType: BoardType; |
| 30 | 28 |
title: string; |
| 31 | 29 |
breadcrumb: { label: string; href?: string }[];
|
| 32 |
- columns: FoxListColumn<BoardPost>[]; |
|
| 33 | 30 |
items: BoardPost[]; |
| 34 | 31 |
query: BoardPostQuery; |
| 35 | 32 |
currentPage: number; |
... | ... | @@ -47,7 +44,6 @@ |
| 47 | 44 |
boardType, |
| 48 | 45 |
title, |
| 49 | 46 |
breadcrumb, |
| 50 |
- columns, |
|
| 51 | 47 |
items, |
| 52 | 48 |
query, |
| 53 | 49 |
currentPage, |
... | ... | @@ -70,7 +66,7 @@ |
| 70 | 66 |
title={title}
|
| 71 | 67 |
breadcrumb={breadcrumb}
|
| 72 | 68 |
caption={title}
|
| 73 |
- columns={columns}
|
|
| 69 |
+ columns={boardPostColumns(boardType, currentPage, query.pageSize)}
|
|
| 74 | 70 |
rows={items}
|
| 75 | 71 |
rowKey={(row) => row.id}
|
| 76 | 72 |
totalCount={totalCount}
|
--- app/(protected)/(basic)/boards/faqs/page.tsx
+++ app/(protected)/(basic)/boards/faqs/page.tsx
... | ... | @@ -2,7 +2,6 @@ |
| 2 | 2 |
import { verifySession } from '@/lib/auth/dal';
|
| 3 | 3 |
import { fetchBoardPosts } from '@/lib/data/repositories/board-post-repository';
|
| 4 | 4 |
import { parseBoardPostQuery } from '@/lib/domain/board-post-query';
|
| 5 |
-import { faqColumns } from '../_components/board-post-columns';
|
|
| 6 | 5 |
import { BoardPostList } from '../_components/board-post-list';
|
| 7 | 6 |
|
| 8 | 7 |
export const metadata: Metadata = { title: 'FAQ' };
|
... | ... | @@ -30,7 +29,6 @@ |
| 30 | 29 |
{ label: '게시판 관리(고객센터)' },
|
| 31 | 30 |
{ label: 'FAQ' },
|
| 32 | 31 |
]} |
| 33 |
- columns={faqColumns(currentPage, query.pageSize)}
|
|
| 34 | 32 |
items={items}
|
| 35 | 33 |
query={query}
|
| 36 | 34 |
currentPage={currentPage}
|
--- app/(protected)/(basic)/boards/inquiries/page.tsx
+++ app/(protected)/(basic)/boards/inquiries/page.tsx
... | ... | @@ -2,7 +2,6 @@ |
| 2 | 2 |
import { verifySession } from '@/lib/auth/dal';
|
| 3 | 3 |
import { fetchBoardPosts } from '@/lib/data/repositories/board-post-repository';
|
| 4 | 4 |
import { parseBoardPostQuery } from '@/lib/domain/board-post-query';
|
| 5 |
-import { inquiryColumns } from '../_components/board-post-columns';
|
|
| 6 | 5 |
import { BoardPostList } from '../_components/board-post-list';
|
| 7 | 6 |
|
| 8 | 7 |
export const metadata: Metadata = { title: '1:1문의' };
|
... | ... | @@ -30,7 +29,6 @@ |
| 30 | 29 |
{ label: '게시판 관리(고객센터)' },
|
| 31 | 30 |
{ label: '1:1문의' },
|
| 32 | 31 |
]} |
| 33 |
- columns={inquiryColumns(currentPage, query.pageSize)}
|
|
| 34 | 32 |
items={items}
|
| 35 | 33 |
query={query}
|
| 36 | 34 |
currentPage={currentPage}
|
--- app/(protected)/(basic)/boards/notices/page.tsx
+++ app/(protected)/(basic)/boards/notices/page.tsx
... | ... | @@ -2,7 +2,6 @@ |
| 2 | 2 |
import { verifySession } from '@/lib/auth/dal';
|
| 3 | 3 |
import { fetchBoardPosts } from '@/lib/data/repositories/board-post-repository';
|
| 4 | 4 |
import { parseBoardPostQuery } from '@/lib/domain/board-post-query';
|
| 5 |
-import { noticeColumns } from '../_components/board-post-columns';
|
|
| 6 | 5 |
import { BoardPostList } from '../_components/board-post-list';
|
| 7 | 6 |
|
| 8 | 7 |
export const metadata: Metadata = { title: '공지사항' };
|
... | ... | @@ -30,7 +29,6 @@ |
| 30 | 29 |
{ label: '게시판 관리(고객센터)' },
|
| 31 | 30 |
{ label: '공지사항' },
|
| 32 | 31 |
]} |
| 33 |
- columns={noticeColumns(currentPage, query.pageSize)}
|
|
| 34 | 32 |
items={items}
|
| 35 | 33 |
query={query}
|
| 36 | 34 |
currentPage={currentPage}
|
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?