You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React表格添加搜索功能的正确实现,是否可以不使用两个useState钩子?

React表格搜索功能优化解答

可以不用两个useState实现更简洁的代码

你的需求完全可以只保留1个存储原始数据的state,不用单独把筛选结果存成state。原因是筛选结果属于派生状态:它的值完全可以通过原始数据 + 搜索关键词计算得到,没必要单独存储在state中,反而增加维护成本。

你可以把原来存储筛选结果的filter state替换为存储用户输入的搜索关键词的state,渲染时直接做过滤即可;如果数据量较大,用useMemo缓存筛选结果避免重复计算即可,优化后的参考代码如下:

import React, { useState, useEffect, useMemo } from 'react';
import axios from 'axios';
import Table from '@mui/material/Table';
import TableHead from '@mui/material/TableHead';
import TableBody from '@mui/material/TableBody';
import TableRow from '@mui/material/TableRow';
import TableCell from '@mui/material/TableCell';
import DeleteIcon from '@mui/icons-material/Delete';
import TextField from '@mui/material/TextField';

export default function ShowProject() {
    const [data, setData] = useState([]);
    // 替换原来的filter state,仅存储用户输入的搜索关键词
    const [searchVal, setSearchVal] = useState('')

    useEffect(() => {
        const fetchData = async () => {
            const result = await axios(
                'http://127.0.0.1:5000/pr'
            );
            setData(result.data);
            // 无需额外同步更新筛选结果
        }
        fetchData()
    }, []);

    // 数据量较大时用useMemo缓存,仅当原始数据或搜索关键词变化时才重新计算筛选结果
    const filteredData = useMemo(() => {
        const searchStr = searchVal.toString().toLowerCase().trim();
        if (!searchStr) return data;
        return data.filter(row => 
            row.customer.toString().toLowerCase().includes(searchStr)
        )
    }, [data, searchVal])
    
    return (
        <div>
            <div>
                <TextField onChange={(e) => setSearchVal(e.target.value)} />
                <Table>
                    <TableHead>
                        <TableRow>
                            <TableCell>Project</TableCell>
                            <TableCell>Code</TableCell>
                            <TableCell>Customer</TableCell>
                            <TableCell></TableCell>
                        </TableRow>
                    </TableHead>
                    <TableBody>
                        {filteredData.map(item => (
                            <TableRow key={item.db_id}>
                                <TableCell>{item.project_name}</TableCell>
                                <TableCell>{item.project_code}</TableCell>
                                <TableCell>{item.customer}</TableCell>
                                <TableCell><DeleteIcon /></TableCell>
                            </TableRow>
                        ))}
                    </TableBody>
                </Table>
            </div>
        </div>
    )
}

如果你的数据量很小(百条级别),甚至可以省略useMemo,直接在渲染时写过滤逻辑即可,代码会更简洁。

原有代码的潜在副作用

  • 状态同步风险:后续如果需要修改原始数据(比如增删改条目),你需要同时更新data和filter两个state,只要漏更其中一个就会出现页面显示和实际数据不一致的问题,维护成本很高。
  • 冗余内存占用:同时存储两份高度相似的数组数据,小数据量下感知不明显,当数据量达到数千、上万条时会产生不必要的内存开销。
  • 逻辑维护成本高:筛选规则和state更新逻辑拆分在两处,后续如果要调整搜索规则(比如新增搜索字段、调整匹配逻辑),需要同步修改筛选逻辑和state赋值逻辑,容易出遗漏。

内容的提问来源于stack exchange,提问作者Alecbalec

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 08:54:04