본문 바로가기
Frontend/React

React Material-UI Sort Table Custom Hook 이용하기

by YERIEL_염주둥 2021. 5. 11.
728x90

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

 

React Table component - Material-UI

Tables display sets of data. They can be fully customized.

material-ui.com

 

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을 사용하면 매번 함수와 변수를 선언하지 않아도 사용 할 수 있답니다.

반응형

댓글