Logo

Material UI의 Table 컴포넌트

웹 페이지에서 많은 양의 데이터를 일목요연하게 보여주기 위해서 테이블(table) UI가 많이 사용됩니다. React로 완성도 있는 테이블 컴포넌트를 개발하려면 이외로 고려할 부분이 많아서 생각보다 많은 시간과 노력이 들어가게 되는데요. 이번 포스팅에서는 Material UI를 이용하여 좀 더 손쉽게 테이블 UI를 구현해보도록 하겠습니다.

Material UI의 기본적인 셋업에 대한 부분은 관련 포스팅를 참고 바랍니다.

필요한 컴포넌트

HTML을 사용해서 테이블의 열과 행의 골격을 만들 때, <table> 엘리먼트 뿐만 아니라, <tr>, <td>, <thead>, <tbody>와 같은 추가적인 엘리먼트가 필요합니다. Material UI를 사용해서 테이블을 구성할 때도 마찬가지로, <Table/> 컴포넌트와 더블어 <TableRow/>, <TableCell/>, <TableHead>, <TableBody>, <TableContainer>와 같은 관련된 컴포넌트를 함께 사용해야 합니다.

import {
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  Paper,
} from "@material-ui/core";

이 모든 컴포넌트는 위와 같이 @material-ui/core 패키지로 부터 한 번에 불러올 수 있습니다.

테스트 데이터

Material UI를 사용하여 많은 사용자의 정보를 보여주는 테이블을 구현해보도록 하겠습니다. 먼저 테스트 데이터가 필요한데요. 랜덤 데이터를 생성해주는 faker 라이브러리를 이용하여 사용자 53명 데이터를 담고 있는 배열을 만들었습니다.

import faker from "faker/locale/ko";

faker.seed(123);

const users = Array(53)
  .fill()
  .map(() => ({
    id: faker.random.uuid(),
    name: faker.name.lastName() + faker.name.firstName(),
    email: faker.internet.email(),
    phone: faker.phone.phoneNumber(),
  }));

기본 테이블

Material UI로 부터 불러온 테이블 관련 컴포넌트와 faker로 발생시킨 테스트 데이터를 이용하여 간단한 사용자 테이블 컴포넌트를 작성해보았습니다.

크게 두 개의 영역으로 나누어지는데 <TableHead/> 컴포넌트는 각 레이블의 이름을 한 줄에 보여주고, <TableBody/> 컴포넌트는 각 레이블에 해당하는 데이터를 루프를 돌면서 여러 줄에 보여줍니다.

function UserTable() {
  return (
    <TableContainer component={Paper}>
      <Table size="small">
        <TableHead>
          <TableRow>
            <TableCell>No</TableCell>
            <TableCell align="right">Name</TableCell>
            <TableCell align="right">Email</TableCell>
            <TableCell align="right">Phone</TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
          {users.map(({ id, name, email, phone }, i) => (
            <TableRow key={id}>
              <TableCell>{i + 1}</TableCell>
              <TableCell align="right">{name}</TableCell>
              <TableCell align="right">{email}</TableCell>
              <TableCell align="right">{phone}</TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </TableContainer>
  );
}

참고로 <Table/> 컴포넌트의 size prop은 기본값이 medium이고 small로 바꾸게 되면 데이터가 좀 더 촘촘하게 표시됩니다.

테이블 페이징

많은 양의 데이터를 테이블로 보여줘야 할 경우, 페이징(paging)을 제공하여 사용자 경험을 개선시킬 수 있습니다. Material UI에서는 이에 특화된 <TablePagination/>라는 별도의 컴포넌트를 제공하고 있는데요. 이 컴포넌트를 <TableFooter/> 컴포넌트로 감싸주면, 기존의 <TableHead/><TableBody/> 영역과 조화롭게 <Table/> 컴포넌트 안에 배치가 됩니다.

페이징을 위해 추가로 필요한 이 두 개의 컴포넌트를 다른 Material UI의 컴포넌트와 동일한 방식으로 불러옵니다.

import {
  // ... 기존 테이블 관련 컴포넌트 ...
  TableFooter,
  TablePagination,
} from "@material-ui/core";

테이블 페이징 구현을 하려면 현재 페이지(page)와 페이자 당 보여줄 열의 수(rowsPerPage)에 대한 상태 관리가 필요합니다. React의 useState 훅 함수를 이용하여 이 두 가지 상태를 저장할 변수와 상태 변경을 위한 함수를 선언해줍니다.

<TablePagination/> 컴포넌트를 사용할 때는 이 상태 값들과 함께, 각 상태가 변경될 때 호출되야 하는 이벤트 핸들러 함수를 prop으로 넘겨줘야 합니다.

function UserTable() {
  const [page, setPage] = useState(0)
  const [rowsPerPage, setRowsPerPage] = useState(10)

  const handleChangePage = (event, newPage) => {
    setPage(newPage)
  }

  const handleChangeRowsPerPage = (event) => {
    setRowsPerPage(parseInt(event.target.value, 10))
    setPage(0)
  }
  return (
    <TableContainer component={Paper}>
      <Table size="small">
        <TableHead>
          <TableRow>
            <TableCell>No</TableCell>
            <TableCell align="right">Name</TableCell>
            <TableCell align="right">Email</TableCell>
            <TableCell align="right">Phone</TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
          {users
            .slice(page * rowsPerPage, (page + 1) * rowsPerPage)
            .map(({ id, name, email, phone }, i) => (
              <TableRow key={id}>
                <TableCell component="th" scope="row">
                  {page * rowsPerPage + i + 1}
                </TableCell>
                <TableCell align="right">{name}</TableCell>
                <TableCell align="right">{email}</TableCell>
                <TableCell align="right">{phone}</TableCell>
              </TableRow>
            ))}
        </TableBody>
        <TableFooter>
          <TableRow>
            <TablePagination
              count={users.length}
              page={page}
              rowsPerPage={rowsPerPage}
              onChangePage={handleChangePage}
              onChangeRowsPerPage={handleChangeRowsPerPage}
            />
          </TableRow>
        </TableFooter>
      </Table>
    </TableContainer>
  )
}

<TableFooter/> 영역에 추가된 것 이외에도 JSX 코드에도 약간의 변화가 필요한데요. <TableBody/> 영역을 보면 자바스크립트의 slice() 함수를 이용하여, 현재 페이지와 페이지 당 보여줄 열의 수에 따라서 테이블에 보여줄 데이터의 양을 조절해주는 코드가 추가되었습니다.

전체 코드

본 포스팅에서 제가 작성한 전체 코드는 아래에서 직접 확인하고 실행해보실 수 있습니다.

마치면서

이상으로 Material UI를 이용해서 어떻게 테이블 UI를 구현하는지에 대해서 간단하게 살펴보았습니다. Material UI의 공식 문서를 참고하시면 각 테이블 관련 컴포넌트에 대해서 좀 더 자세한 부분을 배우실 수 있으실 것입니다.