0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

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

Last updated at Posted at 2024-01-21

簡単的なTable

Table
<table className={tableClass}>
    <TableHeader columns={columns} />
    <TableBody columns={columns} data={data} />
</table>

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

theader

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

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

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

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
image.png

実現
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]);

データやコンテンツを複数のページにわたって

 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

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

trとtdに自動的にclassNameを増加
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;
    }, []);

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}>
                  令和6年1月23日
                </td>
              </tr>
            </>
          )
        }}

image.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?