사실 자유자재는 아니고.. 리액트 테이블로 여러가지는 만들어야하는 상황이 생겼었다 ! 짜여진 리액트 테이블에 커스텀을 더한 테이블 컴포넌트로 분리하고자 하니까 꽤 많은 시간이 걸렸고, 공식 문서를 많이 찾아봐야했다 .. ! ⏤ React-table v7을 이용했습니다 ⏤ 공식 독스에는 문제를 해결할 수 있는 제안이 나와있지 않아서 여기 저기 코드를 붙여보며, 해결했습니다 !
먼저, 여러 페이지에서 사용되는 테이블을 [테이블 인터랙션/테이블] 2 개의 컴포넌트로 분리하고자 했습니다.
( 동일한 템플릿의 인터랙션을 사용한다면 인터랙션+테이블 1개의 컴포넌트로 분리해도 되지만, 동일한 테이블 디자인과 기능에 interaction 의 기능과 ui가 달라지는 경우가 있어서 2개의 컴포넌트 분리 후, 더 큰 단위(page)에서 하나로 묶어주었습니다 )
TableInteraction 컴포넌트
테이블 인터랙션 컴포넌트 같은 경우에는 다른 영향 받지 않게끔 퓨어하게 작성하고자 노력했습니다.
[ 새로고침 / 검색 / select / pagination ]
[ 검색 / 업로드 ]
위와 같은 interaction이 있을 때 클릭하면, 어떤 행동이 일어나야하는지에 대한 onClick 이벤트만 props로 전달 받았습니다. ( interaction 컴포넌트 자체적으로는 독립적임 )
- 코드 예제
const TableInteraction=({
onRefereshClick,
onSearchClick,
....
})=>{
return (
...
{onRefreshClick && <button onClick={onRefreshClick}>새로고침</button>}
{onSearchClick && <button onClick={onSearchClick}>검색</button>}
...
)
}
그래서 interaction 이 필요한 부분은 다른 컴포넌트 개발하는 것 처럼 고민없이 개발할 수 있었다.
Table 개발
테이블 개발 또한 react-table 독스에 나와 있는 방식과 동일하게 개발했다.
달랐던 점은, 기존에는 한 컴포넌트에서 useTable을 선언하고 table 요소에 내려줬다면 테이블은 interaction과 동일하게 자체적으로 useTable을 선언하지 않고, 퓨어하게 작성해주었다.
이렇게 해야 테이블 / 인터랙션 컴포넌트들을 독립적으로 운영하고, 따로따로 커스텀을 하여 더 큰 컴포넌트에서의 병합이 가능해진다.
return (
<table>
<thead>
<tr>
{
headerGroups.map(headerGroup => (
headerGroup.headers.map(column => (
<th {...column}>
{column.render('Header')}
</th>
)
)
}
</tr>
</thead>
<tbody >
{page.map(row=> { <tr>
// 기존에 prepare(row)가 필요하지만, 해주지 않음
{rows.cell.map(row=> <td>{row.render('Cell')}</td>}
</tr>}}
</tbody>
</table>
)
row 맵을 돌면서 prepareRow(row) 를 해주라고 독스에 명시되어있었다.
상위 레벨에서 useTable() 선언 후, useTable의 산출물인 prepareRow() => table 컴포넌트 props에 전달, 테이블 컴포넌트 내에서 prepareRow()를 선언
초기에는 위와 같은 방법으로 했었는데 오류가 계속 발생했다. (아직도 자세한 이유는 잘 모르겠다. props로 잘 전달되는 것을 확인했기 때문에 당연히 될 것 이라 생각했다. )
useTable 관련 커스텀 훅 생성
위에서 prepareRow 에 대한 문제는 useTable 커스텀 훅을 생성하며 해결했다.
커스텀 훅을 제작한 이유는 table / tableInteraction 을 분리된 컴포넌트로 사용하고 있었기 때문에 useTable() 을 상위에서 사용했어야했다. useTable로 그냥 쓸 수도 있었음에도 그렇게 하지 않은 이유는 체크박스☑️에 대한 이유 때문이었다. ⏤ useTable에서 체크박스 유무에 대한 부분을 해결할 수 있다. useTable Toggle
const {
headerGroups,
page,
rows,
prepareRow,
} = useTable(
{
columns,
data,
(hooks) => {
hooks.visibleColumns.push((columns) => [
{
id: 'selection',
Header: ({
getToggleAllRowsSelectedProps,
rows,
toggleAllRowsSelected,
toggleRowSelected,
}) => {
const { indeterminate } = getToggleAllRowsSelectedProps();
const onChangeHeaderCheckbox = (e: any) => {
if (!indeterminate) {
toggleAllRowsSelected(e.target.value.checked);
}
if (indeterminate) {
rows.forEach((row) => {
toggleRowSelected(row.id, false);
});
}
};
return (
<>
<CheckboxCell
{...getToggleAllRowsSelectedProps()}
onChange={onChangeHeaderCheckbox}
/>
</>
);
},
Cell: ({ row }: { row: Row<T> }) => {
return (
<>
<CheckboxCell {...row.getToggleRowSelectedProps()} />
</>
);
},
},
...columns,
]);
},
);
커스텀 훅을 작성하지 않았다면, 체크박스를 이용하는 페이지에서 매번 이정도의 길이를 작성해주어야 하기 때문이다 ! 그래서 훅으로 따로 빼서 checkbox 유무에 대한 것을을 선언해주었고,
useTableInstance({
columns,
data,
enableCheckbox: true,
});
페이지 개발 시에는 위와 같은 훅만 선언해준다면 간편하게 테이블에 필요한 props를 정리해줄 수 있도록 했다.
useTable 와 테이블 컴포넌트가 분리되어 있을 때 prepareRow 오류 해결
useTable 선언부와 테이블 컴포넌트가 분리되어있을 때, prepareRow가 발생한다고 위에 작성해두었었다 ! 그에 대한 해결 방법은 useTable 선언한 곳에서 prepareRow를 해주는 것이다.
// useTable Custom hook.ts
rows.map((row) => prepareRow(row));
map을 돌린다음에 props로 전달해주면 된다.
너무 간단한 해결방안 였는데 🤔 오류가 어디에서 발생하는지 문구가 안나와있어서 이게 문제일거라고 생각도 못했었다... 그냥 useTableInstance 하는 곳에서 필요한 것들은 다 해주고, props로 전달하기 ..~
React-Table 활용
단순히 view를 보여주는 테이블 형식이 아니라, 리액트 테이블을 이용해서 위와 같은 파일브라우저(예시)도 이용이 가능했다.
파일 / 디렉토리인지 확인해서, onClick 이벤트를 통해 path 를 체크해주고 그 path 에 해당하는 백엔드 요청을 보내서, 새로운 table의 data를 갈아끼우는 식으로 하면 된다 🤧 말은 단순하게 말했는데 개발하느라 오래 걸렸었던 것 중에 하나였다.. 😅
react-table을 이용해서 테이블과 관련된 UI를 편하게 구현할 수 있었다. 근데 공식 문서를 읽는 시간도 꽤 걸렸고, Custom하기에 납득되지 않는 오류가 생겨서 많은 시도가 필요했던 것 같다.. 독스가 조금 더 친절했으면 좋겠어요... 그래도 React-table은 useFilters, useSortBy, usePagination 등 테이블과 관련된 많은 동작들을 지원해주기 때문에 그래도, 꽤 괜찮은 라이브러리다.
'TECH' 카테고리의 다른 글
Next.js 환경에 MSW 도입해보기 (0) | 2024.05.19 |
---|---|
Storybook로 커스텀 Document 만들기 (1) | 2024.01.14 |
Storybook 7.0 사용기 (+ Next.js, Typescript, Styled-component) (0) | 2023.07.12 |
프로젝트에 Cypress 도입해보기 ⏤ CRA, 타입스크립트 (0) | 2023.03.14 |