Typescript와 React로 개발을 하던 도중 Grid Table을 구현해야 할 일이 생겨서 이곳저곳 찾아보다가 오픈소스 DevExpress Grid를 알게 되었습니다. Grid 오픈 소스 종류는 많지만 Typescript로 작업 중이여서 이 라이브러리를 쓰게 되었습니다.
우선 React에서 기본적으로 react-table을 가지고 테이블을 만들 수 있습니다. 한번쯤은 react-table을 이용하여 만들어 보았는 것이 좋을것 같아 사용해봤는데, 내가 느낀 장점??은 Customizing 하기에는 유용할 것 같다. 단점은 한번더 하라면 정중히 거절할것 같다.(물론 어쩔수 없이 하겠지만...) 그래서 이번 포스트에서는 쉬운방법인 DevExpress 오픈소스 라이브러리를 이용하여 Grid 레이아웃으로 테이블 생성을 설명하고, 다음 포스트에 react-table을 이용하여 Table을 만드는 법에 대해 설명하겠습니다. (DevExpress-Grid)
DevExtreme Reactive
devexpress.github.io
Installation
npm i --save @devexpress/dx-react-core @devexpress/dx-react-grid
yarn add @devexpress/dx-react-core @devexpress/dx-react-grid
material-ui
npm i --save @devexpress/dx-react-grid-material-ui
yarn add @devexpress/dx-react-grid-material-ui
bootstrap 4
npm i --save @devexpress/dx-react-grid-bootstrap4
yarn add @devexpress/dx-react-grid-bootstrap4
bootstrap 3
npm i --save @devexpress/dx-react-grid-bootstrap3
yarn add @devexpress/dx-react-grid-bootstrap3
Grid Table
위의 사이트에서 볼 수 있듯이 기본적으로 Grid를 이용하여 Table을 만드는 방법은 다음과 같이 간단합니다.
import React from 'react';
import Paper from '@mui/material/Paper';
import { Grid, Table, TableHeaderRow } from '@devexpress/dx-react-grid-material-ui';
const columns = [
{ name: 'id', title: 'ID' },
{ name: 'product', title: 'Product' },
{ name: 'owner', title: 'Owner' },
];
const rows = [
{ id: 0, product: 'DevExtreme', owner: 'DevExpress' },
{ id: 1, product: 'DevExtreme Reactive', owner: 'DevExpress' },
];
export default () => (
<Paper>
<Grid
rows={rows}
columns={columns}
>
<Table />
<TableHeaderRow />
</Grid>
</Paper>
);
Grid
<Grid>는 rows, columns를 props로 가지며 Table에 들어가 데이터를 받습니다.
Table
<Grid>... </Grid> 사이에 <Table/>을 정의해주면 Grid의 Props인 rows, colums를 가지고 테이블을 생성해 줍니다.
만약 이 부분을 react-table로 구현한다면 수많은 th,tr,td가 필요하지만 DevExpress Grid는 <Table />하나로 테이블이 생성이 됩니다.
TableHeaderRow
<TableHeaderRow />는 테이블의 헤더를 생성해주는 부분입니다.
실습
저는 Grid Table을 이용하여 파일 업로드 테이블을 만들기로 하였고 최종 화면은 다음과 같습니다.
GridTable.tsx
import React, { useState } from "react";
import Paper from "@mui/material/Paper";
import {
Grid,
Table,
TableHeaderRow,
TableSelection
} from "@devexpress/dx-react-grid-material-ui";
import UploadButton from "../uploadButton/uploadButton";
import { IntegratedSelection, SelectionState } from "@devexpress/dx-react-grid";
const GridTable: React.FC = () => {
const [selection, setSelection] = useState([]);
const [files, setFiles] = useState([]);
const [columns] = useState([
{ name: "FileName", title: "파일명" },
{ name: "FileSize", title: "파일 크기" },
{ name: "LastModifyDate", title: "마지막 수정 날짜" },
{ name: "UploadDate", title: "업로드 날짜" }
]);
const rowData = files.map((file) => {
const modDate = new Date(file.lastModified);
const nowDate = new Date();
return {
FileName: file.name,
FileSize: file.size,
LastModifyDate: modDate.toISOString(),
UploadDate: nowDate.toISOString()
};
});
const onClickRemove = () => {
let removeFile = [];
selection.forEach((idx) => {
removeFile.push(files[idx]);
});
removeFile.forEach((toRemove) => {
const removeIdx = files.findIndex((file) => file === toRemove);
if (removeIdx > -1) files.splice(removeIdx, 1);
});
setFiles([...files]);
setSelection([]);
};
return (
<div>
<UploadButton
type="file"
files={files}
setFiles={setFiles}
onClickRemove={onClickRemove}
/>
<Paper>
<Grid columns={columns} rows={rowData}>
<SelectionState
selection={selection}
onSelectionChange={setSelection}
/>
<IntegratedSelection />
<Table
columnExtensions={[{ columnName: "FileName", width: "auto" }]}
messages={{ noData: "파일을 업로드 하세요." }}
/>
<TableHeaderRow />
<TableSelection showSelectAll />
</Grid>
</Paper>
</div>
);
};
export default GridTable;
SelectionState
<SelectionState>는 Row를 선택 할 수 있게 Table Body에 체크박스를 생성해줍니다. useState로 selection 배열을 생성하고 체크박스가 체크되면 해당 row의 index를 넘겨줍니다. SelectionState를 사용하기 위해서는 <IntegratedSelection/>을 꼭 사용해야 합니다.
TableSelection
<TableSelection>은 전체 선택 체크 버튼을 생성해줍니다.
UploaButton.tsx
import React from "react";
import { UploadButtonProps } from "./uploadButton.type";
const UploadButton: React.FC<UploadButtonProps> = ({
files,
setFiles,
onClickRemove
}) => {
const hiddenFileInput = React.useRef(null);
const handleChange = (event) => {
const uploadFile = event.target.files;
if (uploadFile.length !== 0) {
setFiles([...files, uploadFile[0]]);
event.target.value = ""; // 이걸 해주지 않으면 업로드 파일 지우고 같은걸로 다시 올렸을 경우 deadLock이 발생한다.
}
};
return (
<div>
<div>
<button onClick={onClickRemove}>선택 삭제</button>
</div>
<input type="file" ref={hiddenFileInput} onChange={handleChange}></input>
</div>
);
};
export default UploadButton;
mystifying-wescoff-qiyr3 - CodeSandbox
mystifying-wescoff-qiyr3 by Devconf using @devexpress/dx-react-core, @devexpress/dx-react-grid, @devexpress/dx-react-grid-material-ui, @emotion/react, @emotion/styled, @material-styled/paper, @mui/icons-material, @mui/material, react
codesandbox.io
'React' 카테고리의 다른 글
React Hook을 이용해 API fetch 및 적용 과정에서 발생한 문제 해결 (2) | 2022.02.18 |
---|