Technology[Front]

React 게시글을 react-table을 이용해 정렬, 페이징처리하기

Thunderland 2022. 3. 23. 09:44

웹서비스는 기본적으로 커뮤니티 기능을 제공하기 때문에 전체 게시글을 보여주거나 게시글 정렬, 페이징처리, 검색기능 등을 제공해야할 필요성이 존재합니다. 이 때 React를 사용하면서 게시글 정렬이나 페이징처리를 react-table 라이브러리의 도움을 받아 손쉽게 구현하는 방법에 대해 알아보겠습니다.

 

(1) React

import React, { useState, useEffect } from 'react';
import { useTable, useSortBy, usePagination } from 'react-table';

const BoardList = () => {
	//보여줄 데이터 저장
  const [dataList, setDataList] = useState([]);

	//저장할 데이터
  let board_1 = board().board;

 function SelectColumnFilter({
  column: { filterValue, setFilter, preFilteredRows, id },
    }) {
  // Calculate the options for filtering
  // using the preFilteredRows
  const options = React.useMemo(() => {
    const options = new Set()
    preFilteredRows.forEach((row) => {
      options.add(row.values[id])
    });
    return [...options.values()]
  }, [id, preFilteredRows]);

  // Render a multi-select box
  return (
    <select
      value={filterValue}
      onChange={(e) => {
        setFilter(e.target.value || undefined)

      }}
    >
      <option value="">All</option>
      {options.map((option, i) => (
        <option key={i} value={option}>
          {option}
        </option>
      ))}
    </select>
  );
}

	//데이터에서 보여줄 내역 표시
 const columns = React.useMemo(
  () => [
    {
      Header: '',
      id: 'no',
      columns: [
        {
          Header: '글번호',
          accessor: (item) => {
            return [item.postTitle, item.postKey]
          },
          //a태그를 이용하여 링크를 걸고 싶을 때 사용
          Cell: (e) => (<a href={`/BoardFreeSee/${e.value[1]}`}> {e.value[1]} </a>
          ),
        },
      ],
    },
    {
      Header: '',
      id: 'title',
      columns: [
        {
          Header: '제목',
          accessor: (item) => {
            return [item.postTitle, item.postKey];
          },
          Cell: (e) => (
          <a href={`/BoardFreeSee/${e.value[1]}`}> {e.value[0]} </a>
          ),
        },
      ],
    },
    {
      Header: '',
      id: 'createDate',
      columns: [
        {
          Header: '등록일',
          accessor: (item) => {
            return item.post_date;
          },
        },
      ],
    },
    {
      Header: '',
      id: 'createuser',
      columns: [
        {
          Header: '작성자',
          accessor: (item) => {
            return item.user.user_id;
          },
        },
      ],
    },
    {
      Header: '',
      id: 'readCount',
      columns: [
        {
          Header: '조회수',
          accessor: (item) => {
            return item.post_view;
          },
        },
      ],
    },
  ],
  []
);

  const data = [];
 
 //dataList 중 자유게시판 게시글에 해당하는 내용을 data 배열에 push
  useEffect(()=>{
      setDataList(board_1.filter((e) => e.post_topic === "자유"));
  }, [board_1]);

    dataList.map((item) => {
      dataList.filter((e) => e.post_topic == "자유");
      data.push(item);
    })

  function Table({ columns, data }) {

    const {
      getTableProps,
      getTableBodyProps,
      headerGroups,
      page,
      prepareRow,
      canPreviousPage,
      canNextPage,
      pageOptions,
      pageCount,
      gotoPage,
      nextPage,
      previousPage,
      setPageSize,
      state: { pageIndex, pageSize },
    } = useTable(
      {
        columns,
        data,
      },
      useSortBy,
      usePagination
    )

    return (
      <>
        <table className="common-table" {...getTableProps()}>
          <thead>
            {headerGroups.map((headerGroup) => (
              <tr {...headerGroup.getHeaderGroupProps()}>
                {headerGroup.headers.map(column => (
                  // Add the sorting props to control sorting. For this example
                  // we can add them into the header props
                  <th className="common-table-header-column" 
                  {...column.getHeaderProps(column.getSortByToggleProps())}>
                    {column.render('Header')}
                    {/* Add a sort direction indicator */}
                    <span className="b__span">
                      {column.isSorted
                        ? column.isSortedDesc
                          ? " 🔽"
                          : " 🔼"
                        : ""}
                    </span>
                  </th>
                ))}
              </tr>
            ))}
          </thead>
          <tbody {...getTableBodyProps()}>
            {page.map(
              (row, i) => {
                prepareRow(row);
                return (
                  <tr {...row.getRowProps()}>
                    {row.cells.map(cell => {
                      return (
                        <td 
                        className="common-table-column" 
                        {...cell.getCellProps()}>
                          {cell.render('Cell')}
                          </td>
                      );
                    })}
                  </tr>
                );
              }
            )}
          </tbody>
        </table>

        <div className="pagination">
        <button className="b__btn" onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
         {'⏪'} 
        </button>{' '}
        <button className="b__btn" onClick={() => previousPage()} disabled={!canPreviousPage}>
          {'◀'}
        </button>{' '}
        <button className="b__btn" onClick={() => nextPage()} disabled={!canNextPage}>
          {'▶'}
        </button>{' '}
        <button className="b__btn" onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
          {'⏩'}
        </button>{' '}
        <span className="b__pspan">
          Page{' '}
          <strong className="b__pst">
            {pageIndex + 1} of {pageOptions.length}
          </strong>{' '}
        </span>
        <span className="b__pspan1">
          | Go to page:{' '}
          <input
            className="b__pinput"
            type="number"
            defaultValue={pageIndex + 1}
            onChange={e => {
              const page = e.target.value ? Number(e.target.value) - 1 : 0
              gotoPage(page)
            }}
            style={{ width: '100px' }}
          />
        </span>{' '}
        <select
          className="b__pselect"
          value={pageSize}
          onChange={e => {
            setPageSize(Number(e.target.value))
          }}
        >
          {[3, 5, 8, 10, 20].map(pageSize => (
            <option key={pageSize} value={pageSize}>
           {pageSize}개 보기
            </option>
          ))}
        </select>
      </div>

        <br />

        <hr/>

      </>
    );
  }

    return (
      <>
        <Table columns={columns} data={data} />
      </>
    );
};

export default BoardList;

위의 코드는 실제 프로젝트에서 일부 발췌한 것으로 실제 사용시 일부 수정해서 사용하시면 됩니다. 보여줄 데이터를 가져와서 useState를 이용해 dataList라는 변수에 set한 후 해당 dataList 중 자유게시판(임의)에 해당하는 데이터만 data라는 배열에 push하여 저장합니다. 이후 React.useMemo를 사용하는 부분에서 배열의 각 columns의 Header에 데이터의 종류를 문자열로 지정하고 accessor에서 data에 저장되어 있는 각 객체의 특정 부분을 return하여 화면에 표시하고 만약 a태그를 이용하여 해당 부분을 클릭했을 때 상세페이지로 이동하게 구현하고 싶으시다면 Cell을 이용해 a태그에서 href속성으로 이동할 주소를 작성합니다. 이후 Table이란 함수에서 앞서 정의했던 columns와 data를 가지고 라이브러리의 내장되어있는 기능에서 useSortBy로 정렬을 구현하고 usePagination으로 페이징을 구현합니다. pageSize는 배열의 숫자 중 하나를 선택해 특정 갯수만 한 페이지에 보일 수 있게 구현할 수 있으므로 해당 배열의 숫자를 조정하시면 되고, 가장 마지막 부분에서 Table에서 columns와 data를 앞서 정의한 변수를 props로 전달하여 해당 함수형태의 Table 컴포넌트가 실행되도록 구현하고 있습니다.

 

이상으로 이번 게시글에서는 React 라이브러리 중 react-table을 이용하여 손쉽게 전체 게시글의 정렬, 페이징처리를 구현하는 방법에 대해 알아보았습니다.