0

我在获取数据的 react-table 文档中使用了本指南。我现在遇到的一个问题是我试图在我的 Table 组件周围包裹一个错误边界,我收到了这个错误:

 Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.

当然,当我不基于过滤器和分页获取数据时,这不是问题,但是当我包含 table 组件的 useeffect 方法时,由于 fetchData 方法会改变状态数据,我会得到无限的重新渲染,例如作为列、过滤器和表数据。

带有 ErrorBoundary 的表组件:

<ErrorBoundary  key={generateStringId()} fallbackRender={props =>
    <ErrorFallback {...props} error_code={PAGE_LOAD}/>
}>
    <Table
        columns={columns}
        data={data}
        fetchData={fetchData}
        status={status}
        pageCount={pageCount}
        availableFilters={availableFilters}
        activeFilters={activeFilters}
    />
</ErrorBoundary>

表组件代码:

import React, {useEffect, useState, useCallback} from 'react';
import {useSortBy,usePagination,useTable,useRowSelect} from "react-table";
import {ErrorBoundary} from "react-error-boundary";
import ErrorFallback from "./ErrorFallback";
import SearchFilterBox from './sub_components/SearchFilterBox'
import {DATATABLE} from "../ErrorCodes";
import "./../css/datatables.scss";
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";

function Table({
                   columns,
                   data,
                   fetchData,
                   loading,
                   clientId,
                   orgId,
                   updateSettingData,
                   updateCellData,
                   deleteCellData,
                   activeFilters,
                   skipPageReset,
                   availableFilters = {},
                   tableSettings = {},
                   useFilters = true,
                   displayPagination = true,
                   displayFooter = false,
                   displayRowSelect = false,
                   rowSelectAction,
                   rowSelectTitle = '',
                   hiddenColumns= ["metadata"],
                   pageCount: controlledPageCount,
                   paginationOptions = [10,25,50,100],
                   contentBesideFilters,
               }) {
    const {
        getTableProps,
        getTableBodyProps,
        headerGroups,
        footerGroups,
        prepareRow,
        page,
        canPreviousPage,
        canNextPage,
        pageOptions,
        pageCount,
        gotoPage,
        nextPage,
        previousPage,
        setPageSize,
        initialState,
        selectedFlatRows,
        // Get the state from the instance
        state: { pageIndex, pageSize, sortBy},
    } = useTable(
        {
            columns,
            data,
            availableFilters,
            updateSettingData,
            updateCellData,
            deleteCellData,
            autoResetPage: !skipPageReset,
            initialState: {
                pageIndex: 0,
                hiddenColumns: 'metadata',
                sortBy: [{
                    id: tableSettings['defaultSort'],
                    desc: false
                }],
            }, // Pass our hoisted table state
            manualPagination: true, // Tell the usePagination
            // hook that we'll handle our own data fetching
            // This means we'll also have to provide our own
            // pageCount.
            pageCount: controlledPageCount,
            manualSortBy: true,
        },
        useSortBy,
        usePagination,
    );

    const [filter, setFilter] = useState({
        search : {
            term : '',
            fields : ''
        },
        dateRange: {
            field: '',
            start: '',
            end: '',
            period: ''
        },
        sort: '',
    });


    if (availableFilters.search !== undefined) {
        console.log("Filters Defined!");
        if(availableFilters.search.columns.length <= 0) {
            console.log("useFilter set to False!")
            useFilters = false;
        }
    }

    // Listen for changes in pagination and use the state to fetch our new data
    useEffect(() => {
        let dataFilter = {
            ...filter,
            sort: sortBy,
        };

        if (typeof fetchData === 'function') {
            fetchData({pageIndex, pageSize, dataFilter, clientId, orgId});

        }

    }, [fetchData, pageIndex, pageSize, filter, sortBy, clientId, orgId]);


    const updateFilters = useCallback((filters) => {
        setFilter(filters);
    });

    // Render the table
    return (
        <>
            <div className="filterContainer">
            <ErrorBoundary
                fallbackRender={props => <ErrorFallback {...props} error_code={DATATABLE}/>}
            >


            <SearchFilterBox
                availableFilters={availableFilters}
                activeFilters={activeFilters}
                onChange={filters => updateFilters(filters)}
                contentBesideFilters={contentBesideFilters}
                settings={tableSettings}
                useFilters={useFilters}
            />


            <table {...getTableProps()}>
                <thead>
                {headerGroups.map(headerGroup => (
                    <tr {...headerGroup.getHeaderGroupProps()}>
                        {headerGroup.headers.map(column => (
                            <th {...column.getHeaderProps(column.getSortByToggleProps())}>
                                {column.render('Header')} {filter.search.fields.includes(column.id)
                                ? <FontAwesomeIcon icon={['fas', 'search']} className={"searchable"}/>
                                : ''}
                                <span>
                    {column.isSorted
                        ? column.isSortedDesc
                            ? <FontAwesomeIcon icon={['fa','caret-up']}/>
                            : <FontAwesomeIcon icon={['fa','caret-down']}/>
                        : ''}
                  </span>
                            </th>
                        ))}
                    </tr>
                ))}
                </thead>
                <tbody {...getTableBodyProps()}>
                {page.map((row, i) => {
                    prepareRow(row);

                    return (
                        <tr {...row.getRowProps()}>
                            {row.cells.map(cell => {
                                let mobileRowName = cell.getCellProps().key.split("_");
                                let classes = mobileRowName[2] === 'Actions' ? 'actionsCol' : '';
                                return <td className={classes} data-label={mobileRowName[2]} {...cell.getCellProps()}>{cell.render('Cell')}</td>
                            })}
                        </tr>
                    )
                })}

                </tbody>
                <tfoot>
                {
                    displayFooter &&
                    footerGroups &&
                    footerGroups.map(group => (
                        <tr {...group.getFooterGroupProps()} style={{"fontWeight":"bold"}}>
                            {group.headers.map(column => (
                                <td {...column.getFooterProps()}>{column.render('Footer')}</td>
                            ))}
                        </tr>
                    ))
                }
                {
                    displayPagination &&
                        (loading ?
                            (<tr><td colSpan="10000">Loading...</td></tr>) :
                            (<tr><td colSpan="10000">
                                Showing {page.length} of about {controlledPageCount * pageSize}{' '}
                                results
                            </td></tr>)
                        )
                }
                </tfoot>
            </table>
                {
                    //todo batch download functionality
                    displayRowSelect &&
                    <button
                        className={`download-documents btn-${selectedFlatRows.length ===0 ?'disabled':'primary'}`}
                        disabled={selectedFlatRows.length === 0}
                        onClick={() => rowSelectAction(selectedFlatRows)}>
                        {rowSelectTitle}
                    </button>
                }
            {/*
        Pagination can be built however you'd like.
        This is just a very basic UI implementation:
      */}
            {displayPagination &&
            <div className="pagination">
                <button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
                    <FontAwesomeIcon icon={['fas','angle-double-left']}/>
                </button>{' '}
                <button onClick={() => previousPage()} disabled={!canPreviousPage}>
                    <FontAwesomeIcon icon={['fas','angle-left']}/>
                </button>{' '}
                <button onClick={() => nextPage()} disabled={!canNextPage}>
                    <FontAwesomeIcon icon={['fas','angle-right']}/>
                </button>{' '}
                <button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
                    <FontAwesomeIcon icon={['fas','angle-double-right']}/>
                </button>{' '}
                <span>
          Page{' '}
                    <strong>
            {pageIndex + 1} of {pageOptions.length}
          </strong>{' '}
        </span>
                <span>
          | Go to page:{' '}
                    <input
                        type="number"
                        defaultValue={pageIndex + 1}
                        onChange={e => {
                            const page = e.target.value ? Number(e.target.value) - 1 : 0
                            gotoPage(page)
                        }}
                        style={{ width: '100px' }}
                    />
        </span>{' '}
                { paginationOptions.length > 1 &&<select
                    value={pageSize}
                    onChange={e => {
                        setPageSize(Number(e.target.value))
                    }}
                >
                    {paginationOptions.map(pageSize => (
                        <option key={pageSize} value={pageSize}>
                            Show {pageSize}
                        </option>
                    ))}
                </select>}
            </div>
            }
            </ErrorBoundary>
            </div>
        </>
    )
}



export default React.memo(Table);
4

1 回答 1

0

不知道您的后端排序层次结构是什么,但根据我们大多数人遵循的标准,就像我们给出属性名称及其排序顺序并根据该标准获取数据

    // try this code instead 
    useEffect(() => {
        // let dataFilter = {
        //     ...filter,
        //     sort: sortBy,
        // };
        fetchData({pageIndex, pageSize, dataFilter, clientId, orgId});


    }, [pageIndex, pageSize, sortBy]);
于 2021-12-06T19:48:33.913 回答