nextjs tanstackreact-table 사용

이명진·2023년 8월 16일
0

드래그로 테이블 넓이를 조절 하기 위해 라이브러리를 선택하게 되었다.

next js 를 사용하기 때문에 chatgpt 에게 추천을 받았는데 가장 추천했던게
tankstackreact-table이라서 선택하고 사용하게 되었다.

공식 홈페이지가 나와 있긴 하지만 영어보다는 한국말이 편해서 벨로그 등을 찾아보려고 했지만 벨로그 정리된 파일들이 없어서 공식 문서를 보고 코드를 보면서 이해하기 위해 노력했다.

일단 원하는 기능이 드래그로 넓이 조절 이었기 때문에 column-sizeing 부분에 들어가서 code pen 으로 어떻게 구동 되는지 확인해보았다.

next js에 그대로 적용하기 위해서 코드를 바로 옮겨 적었다.

import { Box } from '@mui/material';
import {
  useReactTable,
  ColumnResizeMode,
  getCoreRowModel,
  ColumnDef,
  flexRender,
} from '@tanstack/react-table';
import { categoryType } from '.';
import { useReducer, useState } from 'react';
type Props = {
  categoryData: categoryType[];
};
type ChartHead = {
  index: number;
  date: string;
  category: string;
  title: string;
  author: string;
  read: number;
  like: number;
  comments: number;
};

type Person = {
  firstName: string;
  lastName: string;
  age: number;
  visits: number;
  status: string;
  progress: number;
};
const MainChart = ({ categoryData }: Props) => {
  const defaultData: Person[] = [
    {
      firstName: 'tanner',
      lastName: 'linsley',
      age: 24,
      visits: 100,
      status: 'In Relationship',
      progress: 50,
    },
    {
      firstName: 'tandy',
      lastName: 'miller',
      age: 40,
      visits: 40,
      status: 'Single',
      progress: 80,
    },
    {
      firstName: 'joe',
      lastName: 'dirte',
      age: 45,
      visits: 20,
      status: 'Complicated',
      progress: 10,
    },
  ];
  const defaultColumns: ColumnDef<Person>[] = [
    {
      header: 'Name',
      footer: props => props.column.id,
      columns: [
        {
          accessorKey: 'firstName',
          cell: info => info.getValue(),
          footer: props => props.column.id,
        },
        {
          accessorFn: row => row.lastName,
          id: 'lastName',
          cell: info => info.getValue(),
          header: () => <span>Last Name</span>,
          footer: props => props.column.id,
        },
      ],
    },
    {
      header: 'Info',
      footer: props => props.column.id,
      columns: [
        {
          accessorKey: 'age',
          header: () => 'Age',
          footer: props => props.column.id,
        },
        {
          header: 'More Info',
          columns: [
            {
              accessorKey: 'visits',
              header: () => <span>Visits</span>,
              footer: props => props.column.id,
            },
            {
              accessorKey: 'status',
              header: 'Status',
              footer: props => props.column.id,
            },
            {
              accessorKey: 'progress',
              header: 'Profile Progress',
              footer: props => props.column.id,
            },
          ],
        },
      ],
    },
  ];

  const [data, setData] = useState(() => [...defaultData]);
  const [columns] = useState<typeof defaultColumns>(() => [...defaultColumns]);
  const [columnResizeMode, setColumnResizeMode] =
    useState<ColumnResizeMode>('onChange');

  const rerender = useReducer(() => ({}), {})[1];
  const table = useReactTable({
    data,
    columns,
    columnResizeMode,
    getCoreRowModel: getCoreRowModel(),
    debugTable: true,
    debugHeaders: true,
    debugColumns: true,
  });

  return (
    <Box>
      <table {...{ style: { width: table.getCenterTotalSize() } }}>
        <thead>
          {table.getHeaderGroups().map(headerGroup => {
            console.log(headerGroup, 'headerGorup');

            return (
              <tr key={headerGroup.id}>
                {headerGroup.headers.map(header => (
                  <th
                    {...{
                      key: header.id,
                      colSpan: header.colSpan,
                      style: {
                        position: 'relative',
                        width: header.getSize(),
                      },
                    }}
                  >
                    {header.isPlaceholder
                      ? null
                      : flexRender(
                          header.column.columnDef.header,
                          header.getContext()
                        )}
                    <div
                      {...{
                        onMouseDown: header.getResizeHandler(),
                        onTouchStart: header.getResizeHandler(),
                        className: `resizer ${
                          header.column.getIsResizing() ? 'isResizing' : ''
                        }`,
                        style: {
                            transform:
                            columnResizeMode === 'onEnd' &&
                            header.column.getIsResizing()
                              ? `translateX(${
                                  table.getState().columnSizingInfo.deltaOffset
                                }px)`
                              : '',
                        },
                      }}
                    />
                  </th>
                ))}
              </tr>
            );
          })}
        </thead>
        <tbody>
          {table.getRowModel().rows.map(row => (
            <tr key={row.id}>
              {row.getVisibleCells().map(cell => (
                <td
                  {...{
                    key: cell.id,
                    style: {
                      width: cell.column.getSize(),
                    },
                  }}
                >
                  {flexRender(cell.column.columnDef.cell, cell.getContext())}
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </Box>
  );
};

export default MainChart;

처음에는 쭉 훑어보며 필요한 부분만 사용하려고 했는데 테이블은 완성이 되었는데
리사이징이 안되는 것이었다. 그래서 코드펜이 있는 코드를 다 붙여서 확인해봤다.

내가 못한 것인지 코드 문제인지 파악하기 위해서 진행한 결과

마찬가지로 리사이징이 안되었다. 왜 안되는 거지 next.js 라서 그런가 생각을 쭉 하고 코드를 다시 파악하기로 하였다.

className : resizer 이부분이 리사이징을 하는 부분 인것 같아서
쭉 확인하다가 과연 CSS 의 문제가 아닐까 생각하게 되었다.

그래서 style 상으로 border를 넣어서 확인해보니 맞았다.


붉은색 border로 해보니 등장한 resizer!

붉은색 테두리를 쭉 드래그 해보니 정상적으로 작동하게 되었다.

그래서 CSS 문제인것 같아서 style을 다듬어 주기로 했다.

`resizer ${
                          header.column.getIsResizing() ? 'isResizing' : ''
                        }`,
                        style: {
                          position: 'absolute',
                          right: 0,
                          top: 0,
                          height: '100%',
                          width: '5px',
                          background: 'rgba(0, 0, 0, 0.5)',
                          userSelect: 'none',
                          touchAction: 'none',
                          cursor: 'col-resize',
                          border: 'solid red 1px',
                          transform:
 

리사이저 부분에 css 코드를 style 태그로 넣어주었다.

position: absolute 를 해주니 CSS 가 사라지길래 상위 태그에 position : relative 조건을 넣어주니 딱 맞게 CSS가 되었다.

안되는줄 알았는데 CSS 문제로 안되는 거라서 당황스러웠다.

다른 라이브러리를 찾아야 하나 고민했었는데 다행히 해결할수 있었다.

이제 스타일 부분을 건들여 보면서 적용해볼까 한다.

profile
프론트엔드 개발자 초보에서 고수까지!

0개의 댓글