Material-UI를 이용해서 오름차순, 내림차순이 가능한 정렬 테이블을 만드는 중에
React의 장점 중 하나가 component를 재사용 할 수 있는 것인데 Sort 기능을 사용하기위해서 똑같은 함수를 재선언 하여 사용하고 있는 제 자신을 발견 했습니다.
두 개의 자바스크립트 함수에서 같은 로직을 공유하고자 할 때는 또 다른 함수로 분리하여 사용하는데 React는 자신만의 Hook을 만들면 컴포넌트 로직을 함수로 뽑아내어 재사용할 수 있습니다.
컴포넌트와 Hook 또한 함수이기 때문에 같은 방법을 사용할 수 있습니다!
1. Material-UI Sort Table
Material-UI에서 제공하는 Sort Table코드를 제가 사용하기 위해서 분석한 코드 입니다.
SortTableContainer.jsx
//SortTableContainer.jsx
import React from 'react';
import SortTablePresenter from '/SortTablePresenter';
const SortTableContainer = () => {
const [order, setOrder] = useState('desc');
const [orderBy, setOrderBy] = useState('id');
const handleRequestSort = (event, property) => {
const isDesc = orderBy === property && order === 'desc';
setOrder(isDesc ? 'asc' : 'desc');
setOrderBy(property);
};
const desc = (a, b, sequenceBy) => {
if (b[sequenceBy] < a[sequenceBy]) {
return -1;
}
if (b[sequenceBy] > a[sequenceBy]) {
return 1;
}
return 0;
};
const stableSort = (array, cmp) => {
const stabilizedThis = array.map((el, index) => [el, index]);
stabilizedThis.sort((a, b) => {
const sequence = cmp(a[0], b[0]);
if (sequence !== 0) return sequence;
return a[1] - b[1];
});
return stabilizedThis.map((el) => el[0]);
};
const getSorting = (sequence, sequenceBy) => {
return sequence === 'desc'
? (a, b) => desc(a, b, sequenceBy)
: (a, b) => -desc(a, b, sequenceBy);
};
return (
<SortTablePresenter
order={order}
orderBy={orderBy}
handleRequestSort={handleRequestSort}
stableSort={stableSort}
getSorting={getSorting}
/>
);
};
export default SortTableConainter;
SortTablePresenter.jsx
//SortTablePresenter.jsx
import React from 'react';
import {Table, TableHead, TableBody, TableRow, TableCell, TableSortLabel} from '@material-ui/core';
const heads = [
{
id : 'menu',
name : '메뉴',
},
{
id : 'price',
name : '가격'
},
]
const datas = [
{
menu : '아메리카노',
price : '2500',
},
{
menu : '카페라떼',
price : '3000'
},
{
menu : '카푸치노',
pricd : '3200'
}
]
const SortTablePresenter = (props) => {
const {order, orderBy, handleRequestSort, stableSort, getSorting} = props;
const createSortHandler = (property)=>(event) => {
handleRequestSort(event, property);
}
return(
<Table>
<TableHead>
<TableRow>
{heads.map((head)=>(
<TableCell
key={head.id}
sortDirection={orderBy === head.id ? order : false}
>
<TableSortLabel
active={orderBy === head.id}
direction={orderBy === head.id ? order : 'asc'}
onClick={createSortHandler(head.id)}
>
{head.name}
</TableSortLabel>
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{datas !== undefined && (
stableSort(datas, getSorting(order, orderBy))
.map((data)=> (
<TableRow key={data.menu}>
<TableCell>
{data.menu}
</TableCell>
<TableCell>
{data.price}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
)
}
export defaul SortTablePresenter;
매번 다른 테이블을 만들때마다 이런 코드를 짜려면 많이 길고 복잡하고 여러 변수와 함수들이 반복되는 상황을 보게 됩니다.
Material-UI Table이 궁금하신 분들은 아래의 링크에 들어가시면 됩니다.
https://material-ui.com/components/tables/#sorting-amp-selecting
2. 커스텀 Hook 만들기
커스텀 Hook은 이름이 use로 시작하는 자바스크립트 함수입니다.
이름은 반드시 use로 시작해야 하는데 그래야만 한눈에 보아도 Hook 규칙이 적용되는지를 파악할 수 있기 때문입니다. 커스텀 Hook은 조건부 함수가 아니어야 합니다. 무엇을 인수로 받아야 하며 필요하다면 무엇을 반환해야 하는 지를 사용자가 결정할 수 있습니다.
매번 반복 되는 order, orderBy, handleRequestSort, stableSort, getSorting을 커스텀 Hook으로 생성해서 사용해보도록 하겠습니다.
useSortTable.js를 생성합니다.
//useSortTable
import React, {useState} from 'react';
const useSortTable= () => {
const [order, setOrder] = useState('desc');
const [orderBy, setOrderBy] = useState('id');
const handleRequestSort = (event, property) => {
const isDesc = orderBy === property && order === 'desc';
setOrder(isDesc ? 'asc' : 'desc');
setOrderBy(property);
};
const desc = (a, b, sequenceBy) => {
if (b[sequenceBy] < a[sequenceBy]) {
return -1;
}
if (b[sequenceBy] > a[sequenceBy]) {
return 1;
}
return 0;
};
const stableSort = (array, cmp) => {
const stabilizedThis = array.map((el, index) => [el, index]);
stabilizedThis.sort((a, b) => {
const sequence = cmp(a[0], b[0]);
if (sequence !== 0) return sequence;
return a[1] - b[1];
});
return stabilizedThis.map((el) => el[0]);
};
const getSorting = (sequence, sequenceBy) => {
return sequence === 'desc'
? (a, b) => desc(a, b, sequenceBy)
: (a, b) => -desc(a, b, sequenceBy);
};
return [handleRequestSort, stableSort, getSorting, order, orderBy]
};
export default useSortTable;
SortTableContainer에 선언된 변수와 함수들을 그대로 가져왔습니다. 그러고 마지막에 useSortTable에 선언된 변수와 함수들을 return해주면 됩니다.
생각보다 간단하죠?
3. 커스텀 Hook 사용하기
선언된 커스텀 Hook을 이제 사용해볼까요?
SortTableContainer.jsx
//SortTableContainer.jsx
import React from 'react';
import SortTablePresenter from './SortTablePresenter';
import useSortTable from './useSortTable'
const SortTableContainer = () => {
const [handleRequestSort, stableSort, getSorting, order, orderBy] = useSortTable();
return (
<SortTablePresenter
order={order}
orderBy={orderBy}
handleRequestSort={handleRequestSort}
stableSort={stableSort}
getSorting={getSorting}
/>
);
};
export default SortTableConainter;
SortTableContainer.jsx에 선언된 변수와 함수를 모두 아끼지 말고 지웁니다.
위에서 생성한 useSortTable을 임포트 한 후 선언하면 끝
한 눈에 봐도 코드가 깔끔해진게 보이나요? 깔끔도 해졌지만 다른 컴포넌트에 sort Table을 또 만들때도 이 useSortTable을 사용하면 매번 함수와 변수를 선언하지 않아도 사용 할 수 있답니다.
'Frontend > React' 카테고리의 다른 글
[React] Html2Canvas를 이용하여 화면 캡쳐하기 (0) | 2021.07.20 |
---|---|
[React] 페이지 이동시 scroll 복귀 (0) | 2021.05.20 |
[React] 라이브러리 없이 Div Slideshow 구현하기 (0) | 2021.04.30 |
React-Quill Image resize (13) | 2021.04.22 |
Material-UI TextField 속성 error와 JavaScript test()를 이용한 validation (유효성검사) (0) | 2021.03.23 |
댓글