jQuery용 DataTables와 리액트를 함께 사용하는 일은 많이 없을 거라 생각합니다. MUI, Ant Design과 같은 호환성이 좋은 선택지가 이미 있기 때문입니다. 그럼에도 여러 상황에 따라 이 조합을 써야할 경우가 있습니다.(바로 저처럼..) 그런데 사용하면서 느낀 건, 생각보다 강력한 도구라는 것입니다. 테이블 형태로 노출되는 화면을 어떻게 반응형으로 만들어야 할지 막막했는데, 이 부분을 DataTables가 시원하게 해결해주었습니다.
이름에서도 알 수 있듯 DataTables는 jQuery(이하 제이쿼리)에 대한 의존성을 갖습니다.(v1.11부터 non-jQuery 방식으로 초기화가 가능하지만 여전히 제이쿼리에 의존성을 갖고 사용합니다.) 제이쿼리와 리액트 둘 다 DOM(Document Object Model)을 조작하기 때문에 사실 그렇게 좋은 조합은 아니지만 테이블 자체에서만 사용을 한다면 나쁘지 않습니다.
리액트용 레퍼런스가 한글은 거의 뭐 전무하고, 외국 글마저 클래스 컴포넌트로 구현한 자료가 많더군요. 저의 수많은 시행착오와 구글링, 공식 문서/포럼에서 찾은 자료를 통해 배운 것들을 정리 해보았습니다.
기본 사용법
먼저 관련 패키지들을 설치해보겠습니다. 제가 설치한 패키지는 다음과 같습니다.
npm i jquery datatables.net-dt datatables.net-responsive-dt
간단하게 의존성이 있는 (1)제이쿼리, (2)기본값의 데이터테이블 그리고 (3)반응형을 위한 패키지를 설치했습니다. 더 많은 확장 기능을 확인하시려면 DataTables Download를 참고해주세요. NPM 설치 방법 외에도 직접 다운로드, CDN 등으로도 사용 가능합니다.
DataTables 초기 설정
먼저 다운로드한 패키지들을 import 해옵니다. 그 후 초기 설정들을 해보겠습니다. npm에서 다운로드한 js 파일과 css 파일을 import 했습니다.
import $ from 'jquery';
import 'datatables.net-dt';
import 'datatables.net-responsive-dt';
import 'datatables.net-dt/css/jquery.dataTables.min.css';
import 'datatables.net-responsive-dt/css/responsive.dataTables.min.css';
이제 테이블에 필요한 기본적인 것들이 준비가 되었으니 초기화를 해주겠습니다. 제가 생각하는 기본적인 초기화 방법은 다음과 같습니다.
export function DataTable() {
const tableRef = useRef();
useEffect(() => {
const table = $(tableRef.current).DataTable({
data: [
// ...
],
columns: [
// ...
],
responsive: true, // 반응형 켜기
// options
});
// 언마운트 시 destroy
return () => {
table.destroy();
};
}, []);
return <table ref={tableRef} style={{ width: '100%' }}></table>;
}
위 코드는 원본 HTML 테이블에 많은 요소들과 이벤트 리스너, 그리고 기타 수정 사항들을 추가 시켜줍니다(테이블 내 검색 기능과 페이지네이션, 노출시킬 로우의 수, 반응형 테이블 등).
여기서 주의할 점은 cleanup 함수인데요, 언마운트 시에 destroy()
함수를 호출하여 기존(원본)의 HTML 테이블로 만들 수 있습니다. 이것을 통해 다른 테이블로 교체 시 메모리 누수를 방지할 수 있습니다.
data, columns 그리고 반응형 테이블
공식문서에 있는 더미 데이터를 이용해서 데이터와 컬럼을 채워보겠습니다.
data: [
['Suki Burks', 'Developer', 'London', '6832', '2020/10/22', '$114,500'],
// ...
],
columns: [
{ title: 'Name' },
{ title: 'Position' },
{ title: 'Office' },
{ title: 'Extn.' },
{ title: 'Start data' },
{ title: 'Salary' },
],
그럼 다음과 같이 데이터가 노출이 됩니다.
여기서 DataTables는 놀라운 방법으로 모바일 및 태블릿 화면을 다음과 같이 대응을 합니다.
위의 이미지처럼 버튼을 토글하여 숨겨진 컬럼 값들을 확인 할 수 있지만, 세부값들을 즉시 펼치는 것도 가능합니다.
export function DataTable() {
const tableRef = useRef();
useEffect(() => {
const table = $(tableRef.current).DataTable({
data: [
// ...
],
columns: [
// ...
],
responsive: {
details: {
display: $.fn.dataTable.Responsive.display.childRowImmediate,
},
},
// options
});
// 언마운트 시 destroy
return () => {
table.destroy();
};
}, []);
return <table ref={tableRef} style={{ width: '100%' }}></table>;
}
Ajax를 통한 데이터 노출
실제로 사용을 할 때에는 일반적으로 서버와 통신을 하여 데이터를 노출시킬 것입니다. 저는 객체 자료구조로 예시를 들었습니다. 다른 자료 구조의 예시는 Ajax sourced data에서 확인하실 수 있습니다.
// objects.json
{
"data": [
{
"id": "1",
"name": "Tiger Nixon",
"position": "System Architect",
"salary": "$320,800",
"startDate": "2022/09/22",
"office": "Edinburgh",
"extn": "5421"
}
...
]
}
컴포넌트의 코드는 다음과 같이 변경이 됩니다.
export function DataTable() {
const tableRef = useRef();
useEffect(() => {
const table = $(tableRef.current).DataTable({
ajax: {
type: 'GET',
url: 'api/objects.json',
dataType: 'json',
},
columns: [
{ data: 'name', title: 'Name' },
{ data: 'position', title: 'Position' },
{ data: 'office', title: 'Office' },
{ data: 'extn', title: 'Extn.' },
{ data: 'startDate', title: 'Start date' },
{ data: 'salary', title: 'Salary' },
],
responsive: true, // 반응형 켜기
});
// 언마운트 시 destroy.
return () => {
table.destroy();
};
}, []);
return <table ref={tableRef} style={{ width: '100%' }}></table>;
}
변경점이 보이시나요? 생각보다 코드가 깔끔하네요.
function(data, callback, settings)
- data - 요청이 전송되기 전에 호출됩니다. XMLHttpRequest 객체를 조작하여 추가 header를 부여하는 등의 처리를 할 수 있습니다.
- callback - 요청이 완료된 후 호출됩니다. ajax 호출에 대한 성공 또는 실패(에러)에 대해 재정의 할 수 있습니다.
- settings - Data Tables 설정 객체입니다.
여기서 data를 통한 토큰 인증을 예시로 보겠습니다.
ajax: {
type: 'GET',
url: 'api/objects.json',
dataType: 'json',
beforeSend(request) {
request.setRequestHeader('AuthToken', authToken);
},
},
// ...
다른 예시는 DataTables ajax를 참고해주세요.
columns 숫자 포맷 변경
숫자에 대해 포맷을 변경해야할 때도 있습니다. 퍼센트가 될 수도 있고, 가독성을 위해 3자리마다 콤마를 붙일 수도 있으며, 3자리 수까지만 반올림을 하여 소수로 표현할 수도 있습니다.
// numberFormat.js
export function number(num) {
return new Intl.NumberFormat().format(num);
}
export function decimal(num) {
return new Intl.NumberFormat('ko-KR', {
style: 'decimal',
}).format(num);
}
export function percent(num) {
return (
new Intl.NumberFormat('ko-KR', {
style: 'decimal',
}).format(num) + '%'
);
}
다른 방법도 있지만, 함수를 구현 해놓고 아래와 같이 필요할 때마다 불러와서 사용을 하는 것이 더 좋은 것 같습니다.
columns: [
// ...
{
data: 'number',
title: 'Number',
render(data) {
return number(data);
},
},
]
결론
이제 기본적인 사용법은 해당 글로 모두 익히셨길 바랍니다. 처음엔 제대로 된 설득없이 DataTables를 사용하게 되어서 많이 의아했습니다. 하지만 사용할수록 다양한 기능들을 지원한다는 것을 알게 되고, 뛰어난 도구란 것도 느꼈습니다. 마지막으로 전체코드를 보여드리고 마무리 짓겠습니다.
import { useEffect, useRef } from 'react';
import $ from 'jquery';
import './data/datatables'; // imports
// import { number, decimal, percent } from './utils/numberFormat'; 필요한 경우
export function DataTable() {
const tableRef = useRef();
useEffect(() => {
const table = $(tableRef.current).DataTable({
ajax: {
type: 'GET',
url: 'api/objects.json',
dataType: 'json',
},
columns: [
{ data: 'name', title: 'Name' },
{ data: 'position', title: 'Position' },
{ data: 'office', title: 'Office' },
{ data: 'extn', title: 'Extn.' },
{ data: 'startDate', title: 'Start date' },
{ data: 'salary', title: 'Salary' },
],
responsive: true, // 반응형 켜기
scrollX: true,
});
// 언마운트 시 destroy
return () => {
table.destroy();
};
}, []);
return (
<table
ref={tableRef}
className='table stripe row-border order-column table-striped cell-border'
style={{ width: '100%' }}></table>
);
}
참고
datatables.net
Integrating React and Datatables — not as hard as advertised
'React' 카테고리의 다른 글
[React] null vs empty fragment (0) | 2023.05.19 |
---|---|
React에서 셋(Set)으로 체크박스 재정의하기 (2) | 2023.05.14 |
[번역] useEffect 단순화 (5) | 2022.09.12 |
MUI Data grid column default value 설정 방법 (4) | 2022.08.30 |
[React.js] 엘리먼트(Element)와 컴포넌트(Component) (1) | 2021.07.17 |