I’m building a spelling bee app where a user can view a table displaying the history of words they’ve spelled. I’m trying to filter the data to be shown based on values they select with checkboxes (easy, medium, hard).
In my code, I am able to filter the array and console.log() it inside the useEffect just fine, but the problem occurs when I take the new array and use it to update my state. I’m also using Tanstack Table if that matters.
Here is the useEffect()
const ProgressTable = ({ data, isLoading, error }) => {
console.log(data)
const [globalFilter, setGlobalFilter] = useState('')
const [selectedDifficulties, setSelectedDifficulties] = useState([])
const [filteredData, setFilteredData] = useState(data)
useEffect(() => {
if (selectedDifficulties.length) {
let newData = filteredData.filter((row) => {
return selectedDifficulties.includes(row.level)
})
console.log('new', newData)
setFilteredData(newData)
} else {
console.log('old', data)
setFilteredData(data)
}
}, [selectedDifficulties])
Here is how I’m updating the “difficulty” level state
const toggleDifficulty = (level) => {
setSelectedDifficulties((prev) => {
console.log(prev)
return prev.includes(level) ? prev.filter((l) => l !== level) : [...prev, level]
})
}
Which is called on an onChange event for checkboxes.
I’ll also include the rest of the file because apparently this has something to do with early returns, but I’m not seeing anything like that.
import React, { useMemo, useState, useCallback, useEffect } from 'react'
import {
useReactTable,
getCoreRowModel,
getSortedRowModel,
getFilteredRowModel,
getPaginationRowModel,
flexRender,
} from '@tanstack/react-table'
const ProgressTable = ({ data, isLoading, error }) => {
console.log(data)
const [globalFilter, setGlobalFilter] = useState('')
const [selectedDifficulties, setSelectedDifficulties] = useState([])
const [filteredData, setFilteredData] = useState(data)
useEffect(() => {
if (selectedDifficulties.length) {
let newData = filteredData.filter((row) => {
return selectedDifficulties.includes(row.level)
})
console.log('new', newData)
setFilteredData(newData)
} else {
console.log('old', data)
setFilteredData(data)
}
}, [selectedDifficulties])
const columns = useMemo(
() => [
{ accessorKey: 'created_at', header: 'Date' },
{
accessorKey: 'word',
header: 'Word',
cell: ({ row }) => (
<div>
{row.original.level} {row.original.word}
</div>
),
},
{ accessorKey: 'is_correct', header: 'Result' },
{
accessorKey: 'acceptance',
header: 'Acceptance',
cell: ({ row }) => <div>{row.original.acceptance + '%'}</div>,
},
{
accessorKey: 'level',
header: 'Difficulty',
},
],
[],
)
const table = useMemo(
() =>
useReactTable({
data: filteredData || [],
columns,
state: {
globalFilter,
},
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
onGlobalFilterChange: setGlobalFilter,
}),
[data, columns, globalFilter, selectedDifficulties],
)
const toggleDifficulty = (level) => {
setSelectedDifficulties((prev) => {
return prev.includes(level) ? prev.filter((l) => l !== level) : [...prev, level]
})
}
return (
<div className='p-4'>
<div>
<h3>Difficulty</h3>
<label>
<input
type='checkbox'
onChange={() => toggleDifficulty('easy')}
/>
Easy
</label>
<label>
<input
type='checkbox'
onChange={() => toggleDifficulty('medium')}
/>
Medium
</label>
<label>
<input
type='checkbox'
onChange={() => toggleDifficulty('hard')}
/>
Hard
</label>
</div>
<input
placeholder='Search words...'
value={globalFilter}
onChange={(e) => setGlobalFilter(e.target.value)}
className='mb-4'
/>
<table className='w-full border-collapse border'>
<thead className='bg-gray-200'>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<th key={header.id} className='p-2 border cursor-pointer'>
{flexRender(
header.column.columnDef.header,
header.getContext(),
)}
</th>
))}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map((row) => (
<tr key={row.id} className='border'>
{row.getVisibleCells().map((cell) => (
<td key={cell.id} className='p-2 border'>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
))}
</tr>
))}
</tbody>
</table>
<div className='mt-4 flex justify-between'>
<button onClick={() => table.previousPage()} disabled={!table.getCanPreviousPage()}>
Previous
</button>
<span>
Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount()}
</span>
<button onClick={() => table.nextPage()} disabled={!table.getCanNextPage()}>
Next
</button>
</div>
</div>
)
}
export default ProgressTable