๊ท์ฐฎ์ ์ผ์ ๊ฝค๋ ์์ฃผ ์ผ์ด๋๋ค. ์ธ์ฃผ ์์
์ค ํ
์ด๋ธ ์ปดํฌ๋ํธ๋ฅผ ๊ตฌํํด์ผํ๋ ์ผ์ด ์์๊ณ , ๊ธฐ์กด ์ฝ๋๋ Core UI๋ผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๊ณ ์์๋ค. ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ 4.0๋ฒ์ ์ผ๋ก ์
๊ทธ๋ ์ด๋ ๋๋ฉด์ PRO๋ฒ์ ์ด ์๋ก ์๊ฒผ๊ณ , ๊ทธ๋ฅผ ์ํ ๊ธ๋๋๊ธฐ์ ํ
์ด๋ธ ์ปดํฌ๋ํธ๊ฐ ๊ฑธ๋ ค๋ฒ๋ ธ๋ค. ๊ธฐ์กด์ ์ฌ์ฉํ๋ onRowClick
, scopedSlots
๋ฑ์ ๊ธฐ๋ฅ๋ค์ด ์ฌ๋ผ์ก๊ณ ์ง์ ๊ตฌํํด์ผ ํ๋ค.
<Table
paginationState={[current, setCurrent]}
column={column}
data={data}
onRowClick={data => {
navigate(`/notices/${data.id}`);
}}
customCellItem={{
info: data => <button onClick={() => alert(data.index)}>์ปค์คํ
cell</button>,
date: data => <div style={{color: 'red'}}>{data.date}</div>,
}}
/>;
์ถ์ํ๋ Table
์ ์์ ์ปดํฌ๋ํธ๋ ์์ ๊ฐ์ด ์ฌ์ฉํ ์ ์๋ค. ์ปฌ๋ผ๊ณผ data ๋ฐฐ์ด์ ๋๊ฒจ์ฃผ๋ฉด ์ปดํฌ๋ํธ ๋ด๋ถ์ ์ผ๋ก ์ด๋ฌ์ฟต์ ๋ฌ์ฟตํด์ ํ
์ด๋ธ์ ๋ฉ์๊ฒ ๊ทธ๋ ค์ฃผ๋ ๋์์ด ์ถ์ํ๋์ด ์๋ค.
์ปดํฌ๋ํธ ๋ด๋ถ๋ ๊ฐ๋จํ ์ด๋ ๊ฒ ๋์ด ์๋ค. CoreUI์์ ์ ๊ณตํด์ฃผ๋ ์ปดํฌ๋ํธ๋ค์๋ C
๊ฐ ๋ถ์ด์์.
const {content, size, total} = data;
const itemList = customCellItem
? getCustomRow(content, customCellItem)
: content;
return (
<>
<CTable hover striped responsive>
<CTableHead>
<CTableRow>
{column.map(c => (
<CTableHeaderCell scope='col' key={c.key} style={c._style}>
{c.label}
</CTableHeaderCell>
))}
</CTableRow>
</CTableHead>
<CTableBody>
{itemList.map((item, idx) => (
<CTableRow
key={`${item.id}-${idx}`}
onDoubleClick={() => onRowClick?.(item)}
>
{Object.keys(filterRowData(item, column)).map(cell => (
<CTableDataCell key={cell}>{item[cell]}</CTableDataCell>
))}
</CTableRow>
))}
</CTableBody>
</CTable>
<Pagination
current={paginationState[0]}
setCurrentPage={paginationState[1]}
totalPage={Math.ceil(total / size)}
/>
</>
);
props๋ก ๋ฐ์ column๊ณผ item์ ํ
์ด๋ธ row๋ก ๋ ๋๋ง์ํจ๋ค. getCustomRow
ํจ์๋ฅผ ํตํด ๊ฐ cell๋ง๋ค ๋ ๋๋งํ ์ปดํฌ๋ํธ๋ฅผ ์ง์ ์ง์ ํด์ฃผ๊ณ , filterRowData
ํจ์๋ฅผ ํตํด ์๋ฒ์์ response๋ก ๋ฐ์ data ๊ฐ์ฒด๋ฅผ column ๊ฐ์ฒด์ ๋์กฐํด ๋ณด์ฌ์ฃผ๊ณ ์ถ์ ํค-๊ฐ๋ง ํํฐ๋งํ๋ค.
tsx์์ ํจ์์ ์ ๋ค๋ฆญ ์ฌ์ฉํ๊ธฐ
ํ ์ด๋ธ ๊ฐ ํ์ ํด๋ฆญํ์ ๋ ์คํ๋๋ ์ฝ๋ฐฑ ํจ์์, ์ธ์๋ก ๊ฐ ํ์ data๊ฐ ์ ๋ฌ๋๋๋ก ํ๋ค.
๋ฌธ์ ๋ ์ฌ๊ธฐ์ ๋ฐ์ํ ์ ์๋ค.
์ปดํฌ๋ํธ ์ธ๋ถ์์ data๊ฐ ์ด๋ค ํ์ ์ธ์ง ๋ชจ๋ฅด๊ธฐ ๋๋ฌธ์, ๋ฉ์ฒญํ ๊ฐ๋ฐ์๊ฐ ์ถฉ๋ถํ ์ค์ํ ์ ์๋ ์ํฉ์ด ๋ง๋ค์ด์ง๋ค. ํ์ ์คํฌ๋ฆฝํธ์ ์ ๋ค๋ฆญ ํ์ ์ ํตํด Table ์ปดํฌ๋ํธ๋ก ๋๊ธด ํ์ ์ ์ฝ๋ฐฑ์์ ์ถ๋ก ๋์ด ์ ์ ํ ํ์ ์ ์ป์ ์ ์๋ค.
const GenericReturnFunc = <T>(arg: T): T => {
return arg;
๊ทธ๋ฅ ts ํ์ผ์์๋ ์์ ๊ฐ์ด ์ ๋ค๋ฆญ ํจ์๋ฅผ ์ธ ์ ์๋ค. ํ์ง๋ง tsx์์ ์์ ๊ฐ์ด ์์ฑํ๋ฉด ๋นจ๊ฐ์ค์ด ๋จ๋ ๊ฑธ ๋ณผ ์ ์๋ค.
const GenericReturnFunc = <T extends {}>(arg: T): T => {
return arg;
}
์ด๋ ๊ฒ extend
ํค์๋๋ฅผ ์ฌ์ฉํ๊ฑฐ๋,
const GenericReturnFunc = <T,>(arg: T) : T => {
return arg;
}
๋๊ฐ ์ด์์ ํ์ ๋งค๊ฐ๋ณ์๋ฅผ ์ฌ์ฉํ๋ฉด ์ ์์ ์ผ๋ก ์ ๋ค๋ฆญ์ ์ธ์ํ๋ค. ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ ํ์ผ์์ ์์ ๊ฐ์ด ์ผํ๋ฅผ ์ด ์ ๋ค๋ฆญ ํ์ ๋ค์ ์์ฃผ ๋ด์๋๋ฐ, ๋๋์ด ์ ๊ทธ๋ ๊ฒ ์ฐ๋์ง ์์๋ค!
์ปดํฌ๋ํธ์ ์ ๋ค๋ฆญ ์ฌ์ฉํ๊ธฐ
const Table = <T extends Item>({
column,
data,
customCellItem,
paginationState,
onRowClick,
}: TableProps<T>) => {
const {content, size, total} = data;
const itemList = customCellItem
? getCustomRow(content, customCellItem)
: content;
return (
<>
// ...
์์ ๊ฐ์ด ์ปดํฌ๋ํธ ํจ์์ ์ ๋ค๋ฆญ ํ์
์ ์์ฑํด์ฃผ์๋ค.,
๊ฐ ์๋ extends
๋ฅผ ํตํด Item ์ด๋ผ๋ ํ์
์ ํ์ฅํ๊ณ ์๋ค.
export type Item = {
[key: string]: number | string | any;
_props?: CTableRowProps;
};
Item์ ํ
์ด๋ธ ์ปดํฌ๋ํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ด์ฅ๋ ํ์
์ด๋ค.
string์ key๋ก ๊ฐ๋ (๊ต์ฅํ ๋์จํ) ๊ฐ์ฒด์ ํ์
์ด๋ค.
{
itemList.map((item, idx) => (
<CTableRow
key={`${item.id}-${idx}`}
onDoubleClick={() => onRowClick?.(item)}
>
{Object.keys(filterRowData(item, column)).map(cell => (
<CTableDataCell key={cell}>{item[cell]}</CTableDataCell>
))}
</CTableRow>
));
}
์ด๋ฐ ์์ผ๋ก ํค[๊ฐ]์ ์ฌ์ฉํ๊ณ ์๊ธฐ ๋๋ฌธ์, Item ํ์
์ ํ์ฅํด ์ฌ์ฉํ๋ ๊ฒ. ๊ทธ๋ ์ง ์๋ค๋ฉด item์์ id ์์ฑ์ ๊ฐ์ ธ์ค๋ ๊ณผ์ ์์ 'T' ํ์์ 'id' ์์ฑ์ด ์์ต๋๋ค.ts(2339)
์ค๋ฅ๋ฅผ ๋ง์ฃผ์น๊ฒ ๋๋ค.
๊ธ์ ์ฐ๋ค ๋ฐ๊ฒฌํ๋๋ฐ, ํ์ ์คํฌ๋ฆฝํธ ์ด์ฉ๋ฉด ๊ฝค๋ ์น์ ํ ์๋.
export interface CustomCellItem<T> {
[key: string]: (data: T) => ReactNode;
}
export interface TableProps<T> {
column: Column[];
data: TableResponse<T>;
customCellItem?: CustomCellItem<T>;
paginationState: [number, Dispatch<SetStateAction<number>>];
onRowClick?: (data: T) => void;
}
์ด์ ์ปดํฌ๋ํธ์ ์ธํฐํ์ด์ค์ ์ ๋ค๋ฆญ ํ์ ์ ๋๊ฒจ์ค ์ ์๋ค. ๋จ์ํ ํค-๊ฐ ํํ์ ๊ฐ์ฒด๋ผ๋ ์๋ฏธ๋ฅผ ๋ด์ Item ํ์ ์ด ์๋ ์ ํํ data์ ํ์ ์ ๋๊ฒจ ์ฌ์ฉํ ์ ์๊ฒ ๋์๋ค.
๋ฉ์ง ํ ์ด๋ธ ์ปดํฌ๋ํธ ๋ง๋ค๊ธฐ
/**
* ํจ์นญ ๋ฐ์ดํฐ ์ค table column์ ์๋ ๊ฐ๋ง ๋ฐํ
* @param data ์๋ณธ ๋ฐ์ดํฐ (ํจ์นญํ ๋ฐ์ดํฐ)
* @param column table์์ ๋ณด์ฌ์ค column key
*/
const filterRowData = <T extends Item>(
data: T,
column: Column[],
): Partial<T> => {
const map = new Map();
column.forEach(c => {
const key = c.key;
map.set(key, data[key]);
});
return Object.fromEntries(map);
};
data์ ์ฌ๋ฌ ์์ฑ ์ค column์ ์๋ ์์ฑ๋ง ๋จ๊ธด๋ค. Partial<T>
์ ํธ๋ฆฌํฐ ํ์
์ ํตํด ๋ฐํ๊ฐ์ ๋ช
์ํด์ฃผ์๋ค. ๋ช
์ํ์ง ์์ผ๋ฉด ํ์
์ด ์ถ๋ก ๋์ง ์์ any๋ก ๋ํ๋๋ค.
export interface CustomCellItem<T> {
[key: string]: (data: T) => ReactNode;
}
/**
* ๋ฒํผ, input ๋ฑ์ ๋ ๋๋งํ ์ปดํฌ๋ํธ๋ฅผ item์ผ๋ก ๋ฐํ
* @param data ๋ ๋๋งํ data
* @param customCellItem cell์ ๋ ๋๋งํ ์ปดํฌ๋ํธ
*/
const getCustomRow = <T,>(data: T[], customCellItem: CustomCellItem<T>) => {
let customRow = data;
Object.keys(customCellItem).forEach(v => {
customRow = customRow.map(row => {
return {...row, [v]: customCellItem[v](row)};
});
});
return customRow;
};
customCellItem์ ์ํ getCustomRow ํจ์์ด๋ค. ์ธ์๋ก ๋ฐ์ ๊ฐ์ฒด์ ์๋ ์์ฑ๊ณผ ๊ฐ์ ํค๋ฅผ ๊ฐ์ง ์ปฌ๋ผ์ ์ปดํฌ๋ํธ๋ฅผ ๋ฐํํ๋ ํจ์๋ก ๋์ฒด๋๋ค.
์์ฃผ ๋ฉ์ง๊ฒ ํ์ ์ด ์ถ๋ก ๋๋ ๊ฒ์ ๋ณผ ์ ์๋ค.