ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TanStack Table v8 - Merge header cell (헤더 병합)
    Front-end/React 2024. 3. 7. 11:57
    반응형

    TanStack Table v8

     

    이번 리액트 프로젝트에서 처음 사용해보는 라이브러리들이 꽤있다.

    그 중 하나가 TanStack Table이고, 사용한 버전은 v8 이다.

     

    https://tanstack.com/table/latest/docs/introduction

     

    일반적인 테이블은 문서를 봐가면서 따라하면 그리 어렵지 않게 사용할 수 있다.

    그런데 이번에는 중간 중간에 헤더가 합쳐져 있는 것을 구현해야했다.

     

    + Shadcn을 사용했지만 일반 html tag도 상관 없다

     


    일반 테이블 만들기 ( Normal Table )

    일반테이블은 문서를 보면 알 수 있지만 생각 보다 쉽게 할 수 있고 다양하게 커스터마이징도 가능하다.

    기본적으로 React에서 TanStack Table을 사용할 때는 useReactTable이라는 것을 가져와서 사용하게 된다.

    useReactTable

    그리고 그 안에는 options를 넣어서 사용하게 되는데, data, columns 등을 넣어서 사용한다.

    예시를 보면 아래와 같다.

      const table = useReactTable({ data, columns });

     

    그렇다면 data와 columns는 각각 무엇을 의미할까?
    말 그대로 테이블에서 사용할 data와 columns인데, 예시를 보자면 아래와 같다.

     

    <data>

    [
        {
            "userId": 1,
            "userName": "홍길동",
            "userPhoneNumber": 01012345678,
        }
        ...
        ...
    ]

     

     

    <columns>

    interface User {
    	userId: string;
        userName: string;
        userPhoneNumber: string;
    }
    
    const columns: ColumnDef<User>[] = [
      {
        accessorKey: 'userId',
        header: '특정 아이디',
        cell: ({ row }) => {
          const id = row.getValue('userId') ?? '';
    
          if (id > 5) {
            return (
              <p className="text-red-700">{name}</p>
            );
          }
    
          return <p className="text-blue-300">{name}</p>;
        }
      },
      {
        accessorKey: 'userName',
        header: '고객명',
        cell: ({row}) => {
        	return <span>{`${row.original.id} - `${row.getValue()}`}</span>
    	}
      },
      {
        accessorKey: 'userPhoneNumber',
        header: '전화번호',
        cell: ({ row }) => {
          
    
          return (
            <div className="border-2 border-red-300">
              {row.getValue() || '전화번호가 없습니다'}
            </div>
          );
        }
      }
    ]

     

    다른 것보다 TanStack Table을 사용하면서 columns 부분에서 편함을 많이 느꼈다.

    각 columns 안에서 useState, useEffect 같은 hooks 또한 사용 가능해서 cell 안에서 얼마든지 커스터마이징을 한 후에 Table cell로 내보낼 수 있다는 장점이 굉장히 편하게 느껴졌다.

     

     

    병합 헤더 만들기 ( Merge header cell )

    그렇다면 헤더를 병합해서 사용할 수 있는 방법도 알아보자.

    자칫 방법을 잘 못 하면 헤더가 2개의 row로 나뉘어져서 이상하게 보여질 수 있으니 조심하자!

    방법은 기본적인 Table을 만드는 것과 다르지 않지만 columns를 만들 때 추가해줘야할 것이 있다.

     

    우선 createColumnHelper를 import 해오고 이것을 사용해야한다.

    import { createColumnHelper } from '@tanstack/react-table';
    
    const columnHelper = createColumnHelper<User>();
    
    const columns = [
      columnHelper.accessor('userId', {
        id: 'userId',
        header: '유저 아이디',
        cell: (info) => info.getValue(),
        meta: {
          rowSpan: 2
        }
      }),
      columnHelper.group({
        id: 'userInfo', // 그룹아이디를 입력해주세요
        header: '유저 정보', // 2개의 Row 중 상단에 들어갈 그룹 헤더의 제목을 입력해주세요
        columns: [
          columnHelper.accessor((row) => row.userName, {
            id: 'userName',
            cell: (info) => info.getValue(),
            header: '유저명'
          }),
          columnHelper.accessor((row) => row.gender, {
            id: 'gender',
            cell: (info) => info.getValue(),
            header: '성별'
          }),
          columnHelper.accessor('age', {
            id: 'age',
            cell: (info) => info.getValue(),
            header: '나이'
          })
        ]
      }),
      columnHelper.accessor('userPhoneNumber', {
        id: 'userPhoneNumber',
        header: '전화번호',
        cell: (info) => info.getValue(),
        meta: {
          rowSpan: 2
        }
      })
    ]

     

    위처럼 작성해주면 좌우에 rowSpan이 적용되고, 가운데가 병합이 되어있는 헤더를 만날 수 있다.

    하나를 보자면 columnHelper.group 안에서 columnHelper.accessor 안에 보면 row를 이용해서 하는 방법이 있고, id를 사용하는 방법이 있는데 어떤 것으로 하던 무방하다!

     

    여기서 끝이 아니라 Table Header를  렌더링 해주는 부분에 하나 더 추가를 해줘야한다.

    우리는 meta라는 이름으로 rowSpan을 넣어놨으므로 그것을 따로 정의해서 넘겨주어야하는 것이다.

     

      <TableHeader>
        {tableInstance.getHeaderGroups().map((headerGroup, index) => (
          <TableRow key={headerGroup.id} className="bg-blue-200">
            {headerGroup.headers.map((header) => {
              const rowSpan = (header.column.columnDef.meta as any)?.rowSpan;
    
              if (
                !header.isPlaceholder &&
                rowSpan !== undefined &&
                header.id === header.column.id
              ) {
                return null;
              }
    
              return (
                <TableCell key={header.id} colSpan={header.colSpan} rowSpan={rowSpan}>
                  {flexRender(
                    header.column.columnDef.header,
                    header.getContext()
                  )}
                </TableCell>
              );
            })}
          </TableRow>
        ))}
      </TableHeader>

     

    나의 경우 Shadcn을 사용하고 있으므로 이렇게 했다.

    이렇게 넘겨주게 되면 rowSpan이 적용되면서 원하는대로 모양이 나타나게 된다.

    예시

    그래서 모양만 잘 만들면 위와 같이 나타나도록 할 수 있다.

     


     

    어떤 사람들은 Table 만들 때 TanStack Table 사용하지 않으면 못 만들겠다고 하던데, 나도 그 지경까지 온 것 같다.

    편리함을 알아버린 것 같다...

    반응형
Designed by Tistory.