使用 Nextjs 反应 Table 过滤
React Table filtering with Nextjs
我有一个使用 React Table 的组件,但由于某种原因过滤不起作用。
当我在输入字段中输入一个术语时,它会开始过滤 1 毫秒,但什么也没有发生。
我从原始示例中复制了代码:https://codesandbox.io/s/elegant-hugle-nilcb?file=/src/App.js
并且只更改了来自我的 api 的输入数据。这是一个很长的 json 文件,用于测试某种数据库模拟。
我在这里真正想要的只是一个搜索每一行的全局过滤器或一个接受输入并过滤掉 table.
的列过滤器
感谢您的帮助!
无论如何,我的 Table 组件:
import React, { useEffect, useState } from 'react'
import styled from 'styled-components'
import { useTable, useFilters, useGlobalFilter, useAsyncDebounce } from 'react-table'
// A great library for fuzzy filtering/sorting items
import {matchSorter} from 'match-sorter'
const regeneratorRuntime = require("regenerator-runtime");
const axios = require('axios');
// Material UI imports
import TextField from '@material-ui/core/TextField';
import SearchIcon from '@material-ui/icons/Search';
import Table from "@material-ui/core/Table";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
const Styles = styled.div`
padding: 1rem;
table {
border-spacing: 0;
border: 1px solid black;
tr {
:last-child {
td {
border-bottom: 0;
}
}
}
th,
td {
margin: 0;
padding: 0.5rem;
border-bottom: 1px solid black;
border-right: 1px solid black;
:last-child {
border-right: 0;
}
}
}
`
// Define a default UI for filtering
function GlobalFilter({
preGlobalFilteredRows,
globalFilter,
setGlobalFilter,
}) {
const count = preGlobalFilteredRows.length
const [value, setValue] = React.useState(globalFilter)
const onChange = useAsyncDebounce(value => {
setGlobalFilter(value || undefined)
}, 200)
return (
<span>
{' '}
<TextField id="outlined-basic" label="Keresés" variant="outlined"
value={value || ""}
onChange={e => {
setValue(e.target.value);
onChange(e.target.value);
}}
placeholder={`${count} records...`}
style={{
fontSize: '1.1rem',
border: '0',
}}
/>
</span>
)
}
// Define a default UI for filtering
function DefaultColumnFilter({
column: { filterValue, preFilteredRows, setFilter },
}) {
const count = preFilteredRows.length
return (
<TextField id="outlined-basic" label="Keresés" variant="outlined"
value={filterValue || ''}
onChange={e => {
setFilter(e.target.value || undefined) // Set undefined to remove the filter entirely
}}
placeholder={`Search ${count} records...`}
/>
)
}
// This is a custom filter UI for selecting
// a unique option from a list
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>
)
}
// This is a custom filter UI that uses a
// slider to set the filter value between a column's
// min and max values
function SliderColumnFilter({
column: { filterValue, setFilter, preFilteredRows, id },
}) {
// Calculate the min and max
// using the preFilteredRows
const [min, max] = React.useMemo(() => {
let min = preFilteredRows.length ? preFilteredRows[0].values[id] : 0
let max = preFilteredRows.length ? preFilteredRows[0].values[id] : 0
preFilteredRows.forEach(row => {
min = Math.min(row.values[id], min)
max = Math.max(row.values[id], max)
})
return [min, max]
}, [id, preFilteredRows])
return (
<>
<input
type="range"
min={min}
max={max}
value={filterValue || min}
onChange={e => {
setFilter(parseInt(e.target.value, 10))
}}
/>
<button onClick={() => setFilter(undefined)}>Off</button>
</>
)
}
// This is a custom UI for our 'between' or number range
// filter. It uses two number boxes and filters rows to
// ones that have values between the two
function NumberRangeColumnFilter({
column: { filterValue = [], preFilteredRows, setFilter, id },
}) {
const [min, max] = React.useMemo(() => {
let min = preFilteredRows.length ? preFilteredRows[0].values[id] : 0
let max = preFilteredRows.length ? preFilteredRows[0].values[id] : 0
preFilteredRows.forEach(row => {
min = Math.min(row.values[id], min)
max = Math.max(row.values[id], max)
})
return [min, max]
}, [id, preFilteredRows])
return (
<div
style={{
display: 'flex',
}}
>
<input
value={filterValue[0] || ''}
type="number"
onChange={e => {
const val = e.target.value
setFilter((old = []) => [val ? parseInt(val, 10) : undefined, old[1]])
}}
placeholder={`Min (${min})`}
style={{
width: '70px',
marginRight: '0.5rem',
}}
/>
to
<input
value={filterValue[1] || ''}
type="number"
onChange={e => {
const val = e.target.value
setFilter((old = []) => [old[0], val ? parseInt(val, 10) : undefined])
}}
placeholder={`Max (${max})`}
style={{
width: '70px',
marginLeft: '0.5rem',
}}
/>
</div>
)
}
function fuzzyTextFilterFn(rows, id, filterValue) {
return matchSorter(rows, filterValue, { keys: [row => row.values[id]] })
}
// Let the table remove the filter if the string is empty
fuzzyTextFilterFn.autoRemove = val => !val
// Our table component
function InsideTable({ columns, data }) {
const filterTypes = React.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 = React.useMemo(
() => ({
// Let's set up our default Filter UI
Filter: DefaultColumnFilter,
}),
[]
)
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
state,
visibleColumns,
preGlobalFilteredRows,
setGlobalFilter,
} = useTable(
{
columns,
data,
defaultColumn, // Be sure to pass the defaultColumn option
filterTypes,
},
useFilters, // useFilters!
useGlobalFilter // useGlobalFilter!
)
// We don't want to render all of the rows for this example, so cap
// it for this use case
const firstPageRows = rows.slice(0, 100)
return (
<>
<Table {...getTableProps()}>
<TableHead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>
{column.render('Header')}
{/* Render the columns filter UI */}
<div>{column.canFilter ? column.render('Filter') : null}</div>
</th>
))}
</tr>
))}
<tr>
<th
colSpan={visibleColumns.length}
style={{
textAlign: 'center',
}}
>
<GlobalFilter
preGlobalFilteredRows={preGlobalFilteredRows}
globalFilter={state.globalFilter}
setGlobalFilter={setGlobalFilter}
/>
</th>
</tr>
</TableHead>
<tbody {...getTableBodyProps()}>
{firstPageRows.map((row, i) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})}
</tbody>
</Table>
<br />
<div>Showing the first 20 results of {rows.length} rows</div>
</>
)
}
// Define a custom filter filter function!
function filterGreaterThan(rows, id, filterValue) {
return rows.filter(row => {
const rowValue = row.values[id]
return rowValue >= filterValue
})
}
// This is an autoRemove method on the filter function that
// when given the new filter value and returns true, the filter
// will be automatically removed. Normally this is just an undefined
// check, but here, we want to remove the filter if it's not a number
filterGreaterThan.autoRemove = val => typeof val !== 'number'
function FilteredReactTable() {
const columns = React.useMemo(
() => [
{
Header: 'Partner Adatok',
columns: [
{
Header: 'Igénylés azonosítója',
accessor: 'logisticsid',
},
{
Header: 'Partner',
accessor: 'logistics_store',
// Use our custom `fuzzyText` filter on this column
filter: 'fuzzyText',
},
],
},
{
Header: 'Info',
columns: [
{
Header: 'Partner neve',
accessor: 'age',
Filter: SliderColumnFilter,
filter: 'equals',
},
{
Header: 'Város',
accessor: 'visits',
Filter: NumberRangeColumnFilter,
filter: 'between',
},
{
Header: 'Igénylés Időpontja',
accessor: 'logistics_date',
Filter: SelectColumnFilter,
filter: 'includes',
},
{
Header: 'Profile Progress',
accessor: 'progress',
Filter: SliderColumnFilter,
filter: filterGreaterThan,
},
],
},
],
[]
)
const [data, setData] = useState([])
useEffect(()=> {
fetch('http://localhost:3000/api/Logisztika')
.then(response =>response.json())
.then(data => setData(data[2].data))
}, [data])
/* const data = React.useMemo(() => data, []) */
return (
<Styles>
<InsideTable columns={columns} data={data} />
</Styles>
)
}
export default FilteredReactTable;
Table 之所以如此,是因为 useEffect 挂钩的第二个数组参数。
我有一个使用 React Table 的组件,但由于某种原因过滤不起作用。 当我在输入字段中输入一个术语时,它会开始过滤 1 毫秒,但什么也没有发生。 我从原始示例中复制了代码:https://codesandbox.io/s/elegant-hugle-nilcb?file=/src/App.js
并且只更改了来自我的 api 的输入数据。这是一个很长的 json 文件,用于测试某种数据库模拟。 我在这里真正想要的只是一个搜索每一行的全局过滤器或一个接受输入并过滤掉 table.
的列过滤器感谢您的帮助!
无论如何,我的 Table 组件:
import React, { useEffect, useState } from 'react'
import styled from 'styled-components'
import { useTable, useFilters, useGlobalFilter, useAsyncDebounce } from 'react-table'
// A great library for fuzzy filtering/sorting items
import {matchSorter} from 'match-sorter'
const regeneratorRuntime = require("regenerator-runtime");
const axios = require('axios');
// Material UI imports
import TextField from '@material-ui/core/TextField';
import SearchIcon from '@material-ui/icons/Search';
import Table from "@material-ui/core/Table";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
const Styles = styled.div`
padding: 1rem;
table {
border-spacing: 0;
border: 1px solid black;
tr {
:last-child {
td {
border-bottom: 0;
}
}
}
th,
td {
margin: 0;
padding: 0.5rem;
border-bottom: 1px solid black;
border-right: 1px solid black;
:last-child {
border-right: 0;
}
}
}
`
// Define a default UI for filtering
function GlobalFilter({
preGlobalFilteredRows,
globalFilter,
setGlobalFilter,
}) {
const count = preGlobalFilteredRows.length
const [value, setValue] = React.useState(globalFilter)
const onChange = useAsyncDebounce(value => {
setGlobalFilter(value || undefined)
}, 200)
return (
<span>
{' '}
<TextField id="outlined-basic" label="Keresés" variant="outlined"
value={value || ""}
onChange={e => {
setValue(e.target.value);
onChange(e.target.value);
}}
placeholder={`${count} records...`}
style={{
fontSize: '1.1rem',
border: '0',
}}
/>
</span>
)
}
// Define a default UI for filtering
function DefaultColumnFilter({
column: { filterValue, preFilteredRows, setFilter },
}) {
const count = preFilteredRows.length
return (
<TextField id="outlined-basic" label="Keresés" variant="outlined"
value={filterValue || ''}
onChange={e => {
setFilter(e.target.value || undefined) // Set undefined to remove the filter entirely
}}
placeholder={`Search ${count} records...`}
/>
)
}
// This is a custom filter UI for selecting
// a unique option from a list
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>
)
}
// This is a custom filter UI that uses a
// slider to set the filter value between a column's
// min and max values
function SliderColumnFilter({
column: { filterValue, setFilter, preFilteredRows, id },
}) {
// Calculate the min and max
// using the preFilteredRows
const [min, max] = React.useMemo(() => {
let min = preFilteredRows.length ? preFilteredRows[0].values[id] : 0
let max = preFilteredRows.length ? preFilteredRows[0].values[id] : 0
preFilteredRows.forEach(row => {
min = Math.min(row.values[id], min)
max = Math.max(row.values[id], max)
})
return [min, max]
}, [id, preFilteredRows])
return (
<>
<input
type="range"
min={min}
max={max}
value={filterValue || min}
onChange={e => {
setFilter(parseInt(e.target.value, 10))
}}
/>
<button onClick={() => setFilter(undefined)}>Off</button>
</>
)
}
// This is a custom UI for our 'between' or number range
// filter. It uses two number boxes and filters rows to
// ones that have values between the two
function NumberRangeColumnFilter({
column: { filterValue = [], preFilteredRows, setFilter, id },
}) {
const [min, max] = React.useMemo(() => {
let min = preFilteredRows.length ? preFilteredRows[0].values[id] : 0
let max = preFilteredRows.length ? preFilteredRows[0].values[id] : 0
preFilteredRows.forEach(row => {
min = Math.min(row.values[id], min)
max = Math.max(row.values[id], max)
})
return [min, max]
}, [id, preFilteredRows])
return (
<div
style={{
display: 'flex',
}}
>
<input
value={filterValue[0] || ''}
type="number"
onChange={e => {
const val = e.target.value
setFilter((old = []) => [val ? parseInt(val, 10) : undefined, old[1]])
}}
placeholder={`Min (${min})`}
style={{
width: '70px',
marginRight: '0.5rem',
}}
/>
to
<input
value={filterValue[1] || ''}
type="number"
onChange={e => {
const val = e.target.value
setFilter((old = []) => [old[0], val ? parseInt(val, 10) : undefined])
}}
placeholder={`Max (${max})`}
style={{
width: '70px',
marginLeft: '0.5rem',
}}
/>
</div>
)
}
function fuzzyTextFilterFn(rows, id, filterValue) {
return matchSorter(rows, filterValue, { keys: [row => row.values[id]] })
}
// Let the table remove the filter if the string is empty
fuzzyTextFilterFn.autoRemove = val => !val
// Our table component
function InsideTable({ columns, data }) {
const filterTypes = React.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 = React.useMemo(
() => ({
// Let's set up our default Filter UI
Filter: DefaultColumnFilter,
}),
[]
)
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
state,
visibleColumns,
preGlobalFilteredRows,
setGlobalFilter,
} = useTable(
{
columns,
data,
defaultColumn, // Be sure to pass the defaultColumn option
filterTypes,
},
useFilters, // useFilters!
useGlobalFilter // useGlobalFilter!
)
// We don't want to render all of the rows for this example, so cap
// it for this use case
const firstPageRows = rows.slice(0, 100)
return (
<>
<Table {...getTableProps()}>
<TableHead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>
{column.render('Header')}
{/* Render the columns filter UI */}
<div>{column.canFilter ? column.render('Filter') : null}</div>
</th>
))}
</tr>
))}
<tr>
<th
colSpan={visibleColumns.length}
style={{
textAlign: 'center',
}}
>
<GlobalFilter
preGlobalFilteredRows={preGlobalFilteredRows}
globalFilter={state.globalFilter}
setGlobalFilter={setGlobalFilter}
/>
</th>
</tr>
</TableHead>
<tbody {...getTableBodyProps()}>
{firstPageRows.map((row, i) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})}
</tbody>
</Table>
<br />
<div>Showing the first 20 results of {rows.length} rows</div>
</>
)
}
// Define a custom filter filter function!
function filterGreaterThan(rows, id, filterValue) {
return rows.filter(row => {
const rowValue = row.values[id]
return rowValue >= filterValue
})
}
// This is an autoRemove method on the filter function that
// when given the new filter value and returns true, the filter
// will be automatically removed. Normally this is just an undefined
// check, but here, we want to remove the filter if it's not a number
filterGreaterThan.autoRemove = val => typeof val !== 'number'
function FilteredReactTable() {
const columns = React.useMemo(
() => [
{
Header: 'Partner Adatok',
columns: [
{
Header: 'Igénylés azonosítója',
accessor: 'logisticsid',
},
{
Header: 'Partner',
accessor: 'logistics_store',
// Use our custom `fuzzyText` filter on this column
filter: 'fuzzyText',
},
],
},
{
Header: 'Info',
columns: [
{
Header: 'Partner neve',
accessor: 'age',
Filter: SliderColumnFilter,
filter: 'equals',
},
{
Header: 'Város',
accessor: 'visits',
Filter: NumberRangeColumnFilter,
filter: 'between',
},
{
Header: 'Igénylés Időpontja',
accessor: 'logistics_date',
Filter: SelectColumnFilter,
filter: 'includes',
},
{
Header: 'Profile Progress',
accessor: 'progress',
Filter: SliderColumnFilter,
filter: filterGreaterThan,
},
],
},
],
[]
)
const [data, setData] = useState([])
useEffect(()=> {
fetch('http://localhost:3000/api/Logisztika')
.then(response =>response.json())
.then(data => setData(data[2].data))
}, [data])
/* const data = React.useMemo(() => data, []) */
return (
<Styles>
<InsideTable columns={columns} data={data} />
</Styles>
)
}
export default FilteredReactTable;
Table 之所以如此,是因为 useEffect 挂钩的第二个数组参数。