React-table 行和分页的组合未按预期运行
React-table combination of rows and pagination doesn't function as intended
我正在使用 react-table
在 table 中包含行和分页,如本例所示:https://react-table.tanstack.com/docs/examples/row-selection-and-pagination。
我已经按照教程中的说明完成了我的示例,但它没有按预期运行。在它停止更新 selectedRowsId
之前,我只能 select 1 行。取消select该行也不会清除它。我做错了什么?
import React, { useMemo, forwardRef, useRef, useEffect } from "react";
import {
useTable,
useSortBy,
useFilters,
useGlobalFilter,
usePagination,
useRowSelect
} from "react-table";
import matchSorter from "match-sorter";
import '../../static/scss/table.scss'
function DefaultColumnFilter({
column: { filterValue, preFilteredRows, setFilter },
}) {
const count = preFilteredRows.length;
return (
<input
value={filterValue || ""}
onChange={(e) => {
setFilter(e.target.value || undefined); // Set undefined to remove the filter entirely
}}
placeholder={`Search ${count} records...`}
/>
);
}
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>
);
}
function fuzzyTextFilterFn(rows, id, filterValue) {
return matchSorter(rows, filterValue, { keys: [(row) => row.values[id]] });
}
fuzzyTextFilterFn.autoRemove = (val) => !val;
const IndeterminateCheckbox = forwardRef(
({ indeterminate, ...rest }, ref) => {
const defaultRef = useRef()
const resolvedRef = ref || defaultRef
useEffect(() => {
resolvedRef.current.indeterminate = indeterminate
}, [resolvedRef, indeterminate])
return (
<>
<input type="checkbox" ref={resolvedRef} {...rest} />
</>
)
}
)
export default function Table({ data }) {
console.log(data[0].title);
const filterTypes = useMemo(
() => ({
// Add a new fuzzyTextFilterFn filter type.
fuzzyText: fuzzyTextFilterFn,
// Or, override the default text filter to use
// "startWith"
text: (rows, id, filterValue) => {
return rows.filter((row) => {
const rowValue = row.values[id];
return rowValue !== undefined
? String(rowValue)
.toLowerCase()
.startsWith(String(filterValue).toLowerCase())
: true;
});
},
}),
[]
);
const defaultColumn = useMemo(
() => ({
// Let's set up our default Filter UI
Filter: DefaultColumnFilter,
}),
[]
);
const columns = useMemo(
() => [
{
Header: "Naziv",
accessor: "title",
},
{
Header: "Tip",
accessor: "activity_type_id",
Filter: SelectColumnFilter,
filter: "includes",
},
{
Header: "Datum",
accessor: "start_time",
},
{
Header: "Mjesto",
accessor: "location",
},
{
Header: "Organizator",
accessor: "team_id",
Filter: SelectColumnFilter,
filter: "includes",
},
{
Header: "Odgovorna osoba",
accessor: "user_id",
},
],
[]
);
const {
getTableProps,
getTableBodyProps,
headerGroups,
page,
prepareRow,
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
selectedFlatRows,
state: { pageIndex, pageSize, selectedRowIds },
} = useTable(
{
columns,
data,
defaultColumn,
filterTypes,
initialState: { pageIndex: 0 },
},
useFilters,
useGlobalFilter,
useSortBy,
usePagination,
useRowSelect,
hooks => {
hooks.visibleColumns.push(columns => [
// Let's make a column for selection
{
id: 'selection',
// The header can use the table's getToggleAllRowsSelectedProps method
// to render a checkbox
Header: ({ getToggleAllPageRowsSelectedProps }) => (
<div>
<IndeterminateCheckbox {...getToggleAllPageRowsSelectedProps()} />
</div>
),
// The cell can use the individual row's getToggleRowSelectedProps method
// to the render a checkbox
Cell: ({ row }) => (
<div>
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
</div>
),
},
...columns,
])
}
);
return (
<div>
<legend className="legend">Popis aktivnosti</legend>
<>
<pre>
<code>
{JSON.stringify(
{
pageIndex,
pageSize,
pageCount,
canNextPage,
canPreviousPage,
},
null,
2
)}
</code>
</pre>
<table {...getTableProps()}>
<thead>
{
// Loop over the header rows
headerGroups.map((headerGroup) => (
// Apply the header row props
<tr {...headerGroup.getHeaderGroupProps()}>
{
// Loop over the headers in each row
headerGroup.headers.map((column) => (
// Apply the header cell props
<th
{...column.getHeaderProps(
column.getSortByToggleProps()
)}
>
{
// Render the header
column.render("Header")
}
<span>
{column.isSorted
? column.isSortedDesc
? " "
: " "
: ""}
</span>
</th>
))
}
{}
<th>Nige</th>
<th>Nei</th>
</tr>
))
}
{
// Loop over the header rows
headerGroups.map((headerGroup) => (
// Apply the header row props
<tr {...headerGroup.getHeaderGroupProps()}>
{
// Loop over the headers in each row
headerGroup.headers.map((column) => (
// Apply the header cell props
<th>
<div>
{column.canFilter ? column.render("Filter") : null}
</div>
</th>
))
}
{}
<th></th>
<th></th>
</tr>
))
}
</thead>
{/* Apply the table body props */}
<tbody {...getTableBodyProps()}>
{page.map((row, i) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})}
</tbody>
</table>
<div className="pagination">
<button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
{"<<"}
</button>{" "}
<button onClick={() => previousPage()} disabled={!canPreviousPage}>
{"<"}
</button>{" "}
<button onClick={() => nextPage()} disabled={!canNextPage}>
{">"}
</button>{" "}
<button
onClick={() => gotoPage(pageCount - 1)}
disabled={!canNextPage}
>
{">>"}
</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>{" "}
<select
value={pageSize}
onChange={(e) => {
setPageSize(Number(e.target.value));
}}
>
{[10, 20, 30, 40, 50].map((pageSize) => (
<option key={pageSize} value={pageSize}>
Show {pageSize}
</option>
))}
</select>
</div>
<p>Selected Rows: {Object.keys(selectedRowIds).length}</p>
<pre>
<code>
{JSON.stringify(
{
selectedRowIds: selectedRowIds,
'selectedFlatRows[].original': selectedFlatRows.map(
d => d.original
),
},
null,
2
)}
</code>
</pre>
</>
</div>
);
}
我找到了解决方案。 index.js 文件包含 <React.StrictMode>
包装 <App />
。删除 <React.StrictMode>
修复它并正常运行。这可能是一个错误,应该修复。
我正在使用 react-table
在 table 中包含行和分页,如本例所示:https://react-table.tanstack.com/docs/examples/row-selection-and-pagination。
我已经按照教程中的说明完成了我的示例,但它没有按预期运行。在它停止更新 selectedRowsId
之前,我只能 select 1 行。取消select该行也不会清除它。我做错了什么?
import React, { useMemo, forwardRef, useRef, useEffect } from "react";
import {
useTable,
useSortBy,
useFilters,
useGlobalFilter,
usePagination,
useRowSelect
} from "react-table";
import matchSorter from "match-sorter";
import '../../static/scss/table.scss'
function DefaultColumnFilter({
column: { filterValue, preFilteredRows, setFilter },
}) {
const count = preFilteredRows.length;
return (
<input
value={filterValue || ""}
onChange={(e) => {
setFilter(e.target.value || undefined); // Set undefined to remove the filter entirely
}}
placeholder={`Search ${count} records...`}
/>
);
}
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>
);
}
function fuzzyTextFilterFn(rows, id, filterValue) {
return matchSorter(rows, filterValue, { keys: [(row) => row.values[id]] });
}
fuzzyTextFilterFn.autoRemove = (val) => !val;
const IndeterminateCheckbox = forwardRef(
({ indeterminate, ...rest }, ref) => {
const defaultRef = useRef()
const resolvedRef = ref || defaultRef
useEffect(() => {
resolvedRef.current.indeterminate = indeterminate
}, [resolvedRef, indeterminate])
return (
<>
<input type="checkbox" ref={resolvedRef} {...rest} />
</>
)
}
)
export default function Table({ data }) {
console.log(data[0].title);
const filterTypes = useMemo(
() => ({
// Add a new fuzzyTextFilterFn filter type.
fuzzyText: fuzzyTextFilterFn,
// Or, override the default text filter to use
// "startWith"
text: (rows, id, filterValue) => {
return rows.filter((row) => {
const rowValue = row.values[id];
return rowValue !== undefined
? String(rowValue)
.toLowerCase()
.startsWith(String(filterValue).toLowerCase())
: true;
});
},
}),
[]
);
const defaultColumn = useMemo(
() => ({
// Let's set up our default Filter UI
Filter: DefaultColumnFilter,
}),
[]
);
const columns = useMemo(
() => [
{
Header: "Naziv",
accessor: "title",
},
{
Header: "Tip",
accessor: "activity_type_id",
Filter: SelectColumnFilter,
filter: "includes",
},
{
Header: "Datum",
accessor: "start_time",
},
{
Header: "Mjesto",
accessor: "location",
},
{
Header: "Organizator",
accessor: "team_id",
Filter: SelectColumnFilter,
filter: "includes",
},
{
Header: "Odgovorna osoba",
accessor: "user_id",
},
],
[]
);
const {
getTableProps,
getTableBodyProps,
headerGroups,
page,
prepareRow,
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
selectedFlatRows,
state: { pageIndex, pageSize, selectedRowIds },
} = useTable(
{
columns,
data,
defaultColumn,
filterTypes,
initialState: { pageIndex: 0 },
},
useFilters,
useGlobalFilter,
useSortBy,
usePagination,
useRowSelect,
hooks => {
hooks.visibleColumns.push(columns => [
// Let's make a column for selection
{
id: 'selection',
// The header can use the table's getToggleAllRowsSelectedProps method
// to render a checkbox
Header: ({ getToggleAllPageRowsSelectedProps }) => (
<div>
<IndeterminateCheckbox {...getToggleAllPageRowsSelectedProps()} />
</div>
),
// The cell can use the individual row's getToggleRowSelectedProps method
// to the render a checkbox
Cell: ({ row }) => (
<div>
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
</div>
),
},
...columns,
])
}
);
return (
<div>
<legend className="legend">Popis aktivnosti</legend>
<>
<pre>
<code>
{JSON.stringify(
{
pageIndex,
pageSize,
pageCount,
canNextPage,
canPreviousPage,
},
null,
2
)}
</code>
</pre>
<table {...getTableProps()}>
<thead>
{
// Loop over the header rows
headerGroups.map((headerGroup) => (
// Apply the header row props
<tr {...headerGroup.getHeaderGroupProps()}>
{
// Loop over the headers in each row
headerGroup.headers.map((column) => (
// Apply the header cell props
<th
{...column.getHeaderProps(
column.getSortByToggleProps()
)}
>
{
// Render the header
column.render("Header")
}
<span>
{column.isSorted
? column.isSortedDesc
? " "
: " "
: ""}
</span>
</th>
))
}
{}
<th>Nige</th>
<th>Nei</th>
</tr>
))
}
{
// Loop over the header rows
headerGroups.map((headerGroup) => (
// Apply the header row props
<tr {...headerGroup.getHeaderGroupProps()}>
{
// Loop over the headers in each row
headerGroup.headers.map((column) => (
// Apply the header cell props
<th>
<div>
{column.canFilter ? column.render("Filter") : null}
</div>
</th>
))
}
{}
<th></th>
<th></th>
</tr>
))
}
</thead>
{/* Apply the table body props */}
<tbody {...getTableBodyProps()}>
{page.map((row, i) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})}
</tbody>
</table>
<div className="pagination">
<button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
{"<<"}
</button>{" "}
<button onClick={() => previousPage()} disabled={!canPreviousPage}>
{"<"}
</button>{" "}
<button onClick={() => nextPage()} disabled={!canNextPage}>
{">"}
</button>{" "}
<button
onClick={() => gotoPage(pageCount - 1)}
disabled={!canNextPage}
>
{">>"}
</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>{" "}
<select
value={pageSize}
onChange={(e) => {
setPageSize(Number(e.target.value));
}}
>
{[10, 20, 30, 40, 50].map((pageSize) => (
<option key={pageSize} value={pageSize}>
Show {pageSize}
</option>
))}
</select>
</div>
<p>Selected Rows: {Object.keys(selectedRowIds).length}</p>
<pre>
<code>
{JSON.stringify(
{
selectedRowIds: selectedRowIds,
'selectedFlatRows[].original': selectedFlatRows.map(
d => d.original
),
},
null,
2
)}
</code>
</pre>
</>
</div>
);
}
我找到了解决方案。 index.js 文件包含 <React.StrictMode>
包装 <App />
。删除 <React.StrictMode>
修复它并正常运行。这可能是一个错误,应该修复。