table ゼロからReact コンポーネントライブラリ(3)

#### 簡単的なTable

```react: Table
<table className={tableClass}>
    <TableHeader columns={columns} />
    <TableBody columns={columns} data={data} />
</table>
```
```javascript

const columns = [
  { key: 'ア', title: 'ア', rowSpan: 3 },
  { key: 'イ', title: 'イ', rowSpan: 3 },
  { key: 'ウ', title: 'ウ', rowSpan: 3 },
  {
    key: 'エ', title: 'エ', colSpan: 2, 
    children: [ // 多次元データを一次元に変換し ITableColumn[][] => ITableColumn[]
      {
        key: 'エア', title: 'エア', colSpan: 2,
        children: [
          { key: 'エアア', title: 'エアア' },
          { key: 'エアオ', title: 'エアオ' }
        ]
      }
    ]
  },
]

const data = [
  { key: 'ア', value: '1' },
  { key: 'イ', value: '2' },
  { key: 'ウ', value: '3' },
  { key: 'エ', value: '4' },
  { key: 'エア', value: '41' },
  { key: 'エアア', value: '4111' },
  { key: 'エアオ', value: '412' },
];
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641430/247a8783-c5c8-4aa4-561f-1290a03ac5bc.png)

#### theader
特殊なデータ処理を行い、多次元データを一次元に変換し、表ヘッダーの作成を簡略化します。

```react: TableHeader
export const setDataEntries = (columns: ITableColumn[], dataEntries: ITableColumn[][] = [], lv: number = 0) => {
    dataEntries[lv] = dataEntries[lv] || [];
    columns.forEach((item: ITableColumn) => {
        dataEntries[lv].push(item);
        if (item.children) {
            return setDataEntries(item.children, dataEntries, lv + 1);
        }
    })
    return dataEntries;
}
```

#### tbody
同じです。一次元のデータにより、順番にレンダリングする

```react: TableBody
export const setDataEntries = (columns: ITableColumn[], dataEntries: string[] = []) => {
    columns.forEach((item: ITableColumn) => {
        if (item.children) {
            return setDataEntries(item.children, dataEntries);
        } else {
            if (dataEntries.every(key => key !== item.key)) {
                dataEntries.push(item.key)
            }
        }
    })
    return dataEntries;
}
```

#### pagination

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641430/8c04491a-fd86-0843-3356-a4a6d5ab2af2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641430/271fb6b7-de39-2bca-4ccf-7fc92c0273ee.png)

```react: 実現
const createpPaginationItems = useCallback(() => {
        const paginationItem = new Array(maxPage).fill(1).map((i, index: number) => {
            const currentPage: number = index + 1;
            return (
                <div
                    key={index}
                    className={
                        paginationItemClass +
                        (page === currentPage ? ' ' + styles["pagination-item-active"] : '')
                    }
                    onClick={() => {
                        setPage(currentPage);
                        onPaginationChange?.(currentPage);
                    }}
                >{index + 1}</div>
            )
        });
        if (maxPage === 1) {
            return paginationItem;
        }
        const showCount: number = 5;
        if (page < showCount) {
            paginationItem.splice(
                maxPage - showCount,
                maxPage - showCount - 1,
                <EllispsePaginationItem
                    paginationItemClass={paginationItemClass}
                    keyName='rightEllispse'
                />
            );
        } else if (page > maxPage - showCount + 1) {
            paginationItem.splice(
                1,
                maxPage - showCount - 1,
                <EllispsePaginationItem
                    paginationItemClass={paginationItemClass}
                    keyName='leftEllispse'
                />
            );
        } else {
            const half = Math.floor(showCount / 2);
            paginationItem.splice(
                page + half,
                maxPage - page - half - 1,
                <EllispsePaginationItem
                    paginationItemClass={paginationItemClass}
                    keyName='rightEllispse'
                />
            );
            paginationItem.splice(
                1,
                page - half - 1,
                <EllispsePaginationItem
                    paginationItemClass={paginationItemClass}
                    keyName='leftEllispse'
                />
            );
        }
        return paginationItem;
    }, [maxPage, page]);
```

データやコンテンツを複数のページにわたって
```react
 const [dataKey, setDataKey] = useState<string[]>([]);
    const [showData, setShowData] = useState<ITableDataItem[][]>([]);

    useEffect(() => {
        setDataKey(setDataEntries(columns));
    }, [columns]);

    useEffect(() => {
        if (data.length > pageSize) {
            setShowData(data.slice((page - 1) * pageSize, page * pageSize));
        }else{
            setShowData(data);
        }
    }, [data, pageSize, page]);

```

#### tfooter

```react: tfooter
renderTFooter={(data, columns) => {
          return (
            <tr>
              <td>会計：</td>
              <td colSpan={4}>
                {
                  data.reduce((a, c) => {
                    return a + c.reduce((f, g) => f + g.value, 0);
                  }, 0)
                }
              </td>
            </tr>
          )
}}

```

![1706015226468.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641430/2db6c03b-0860-0c93-d7ab-964936aa089b.png)

##### trとtdに自動的にclassNameを増加

```react: addElementClass
const addElementClass = useCallback((ele: ReactElement): ReactElement => {
        const { className: preClassName = '', children: preChildren = [] } = ele.props || {};
        let children: ReactElement[] | null = [];
        let className: string | null = '';
        if (preChildren) {
            const len = preChildren.length;
            if (len) {
                for (let i = 0; i < len; i++) {
                    const node = preChildren[i]?.props?.children;
                    if (typeof node !== 'object') {
                        children?.push(preChildren[i]);
                    } else {
                        children?.push(addElementClass(preChildren[i]));
                    }
                }
            } else {
                children?.push(preChildren);
            }
        }

        if (ele.type == 'tr') {
            className = preClassName + ` ${trClass}`;
        }
        if (ele.type == 'td') {
            className = preClassName + ` ${tdClass}`;
        }
        const newElement = React.createElement(ele.type, {
            ...ele.props,
            className,
            children,
        });
        return newElement;
    }, []);
```

```react

renderTFooter={(data, columns) => {
          return (
            <>
              <tr className='abc' onClick={console.log}>
                <td>会計：</td>
                <td colSpan={4}>
                  {
                    data.reduce((a, c) => {
                      return a + c.reduce((f, g) => f + g.value, 0);
                    }, 0)
                  }
                </td>
              </tr>
              <tr>
              <td colSpan={1}>製表日：</td>
                <td colSpan={4}>
                  令和６年１月23日
                </td>
              </tr>
            </>
          )
        }}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3641430/a65f887e-ad94-337b-0612-fd8b40d9e634.png)