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

React Table添加筛选条件后选中行隐藏功能失效问题

问题根因

你传内联filter给Table的时候,根本没把hidden状态的过滤逻辑加进去,当然藏不住选中行。
你之前写的matchData之所以能正常隐藏,是因为它专门做了一层过滤:把id存在hidden里的行全部排除了。但你现在写的内联filter只判断了applyStatus和showGood两个条件,完全没处理hidden状态,点按钮后id确实存进hidden了,但渲染数据源的时候没排除这些行,自然看不到隐藏效果。
除此之外你代码里还有3个会导致功能异常的严重问题:

  • 你在组件渲染顶层直接写了if (menus.apply === 0) setApplyStatus(true)这类逻辑:menus是数组,根本没有apply属性,这两个判断永远不会触发;而且在渲染阶段直接调用state setter会触发无限重渲染,直接导致页面报错。
  • 你写了个依赖为menus的useEffect,回调里又调用setMenus修改menus的值,会触发死循环:menus变更→执行effect→修改menus→menus再次变更→再次执行effect,页面直接卡死。
  • 你定义matchData的时候语法错误,多了左括号少了右括号,本身就跑不起来。
修复步骤
  1. 删掉组件顶层那两个错误的setApplyStatus判断,applyStatus如果没有特殊的切换需求就不要单独存state,直接把判断逻辑合并到数据过滤里即可;如果需要切换,加对应的控制开关,绝对不能在渲染阶段直接改state。
  2. 删掉那个会触发死循环的排序useEffect,排序逻辑直接合并到数据处理流程里,不要直接修改原始的menus状态。
  3. 把所有过滤逻辑(隐藏行判断、apply字段过滤、口味过滤)、排序逻辑用useMemo合并计算,生成最终的表格数据源,不要写内联filter漏逻辑。
  4. 修正语法错误,列定义和表格数据分开命名避免混淆。

修复后的核心代码见下方:

export default function MenuDisplay() {
  const { menuId } = useParams();
  const [selected, setSelected] = useState({});
  const [hidden, setHidden] = useState({});
  const [menus, setMenus] = useState([])
  const [showGood, setShowGood] = useState(false);
  // 移除原有错误的applyStatus状态及顶层修改逻辑,如需切换过滤规则可新增对应开关state

  // 接口请求逻辑保留
  useEffect(() => {
    axios.post("", { menuId: parseInt(menuId) })
      .then(res => setMenus(res.data.menus))
      .catch(err => console.log(err))
  }, [menuId]);

  // 按钮状态判断逻辑保留
  const buttonMode = Object.values(selected).some(isSelected => isSelected)
    ? "apply"
    : "cancel";

  // 行选择逻辑保留
  const rowSelectHandler = (id) => (checked) => {
    setSelected(selected => ({ ...selected, [id]: checked }));
  };

  // 按钮点击逻辑保留
  const handleClick = () => {
    if (buttonMode === "apply") {
      const currentlySelected = {};
      Object.entries(selected).forEach(([id, isSelected]) => {
        if (isSelected) currentlySelected[id] = isSelected;
      });
      setHidden({ ...hidden, ...currentlySelected });
      const newSelected = {};
      Object.keys(selected).forEach(id => newSelected[id] = false);
      setSelected(newSelected);
    } else {
      const currentlyHidden = {};
      Object.entries(hidden).forEach(([id, isHidden]) => {
        if (isHidden) currentlyHidden[id] = isHidden;
      });
      setSelected({ ...selected, ...currentlyHidden });
      const newHidden = {};
      Object.keys(hidden).forEach(id => newHidden[id] = false);
      setHidden(newHidden);
    }
  };

  // 合并所有过滤、排序逻辑,用useMemo缓存避免重复计算
  const tableData = useMemo(() => {
    // 第一步:过滤已隐藏的行
    let result = menus.filter(({ _id }) => !hidden[_id]);
    // 第二步:过滤apply字段,排除apply=1的行,如需切换规则可在此处加判断
    result = result.filter(i => i.apply !== 1);
    // 第三步:按showGood开关过滤口味
    if (!showGood) result = result.filter(i => i.taste !== "Good");
    // 第四步:排序,Good口味的行靠前,替换原有死循环的排序逻辑
    const goodMenus = result.filter(i => i.taste === "Good");
    const restMenus = result.filter(i => i.taste !== "Good");
    return [...goodMenus, ...restMenus];
  }, [menus, hidden, showGood]);

  // 行样式逻辑保留
  const getRowProps = (row) => ({
    style: { backgroundColor: selected[row.values.id] ? "lightgrey" : "white" }
  });

  // 列定义(原代码里命名为data容易和表格数据混淆,改名为columns)
  const columns = [
    {
      Header: "id",
      accessor: (row) => row._id
    },
    {
      Header: "Name",
      accessor: (row) => <Link to={{ pathname: `/menu/${menuId}/${row._id}` }}>{row.name}</Link>
    },
    {
      Header: "Description",
      accessor: (row) => row.description
    },
    {
      Header: "Dishes",
      accessor: (row) => row.dishes,
      id: "dishes",
      Cell: ({ value }) => value && Object.values(value[0]).join(", ")
    },
    {
      Header: "Status",
      accessor: (row) => row.status
    },
    {
      Header: "Show",
      accessor: (row) => <Toggle value={selected[row._id]} onChange={rowSelectHandler(row._id)} />
    }
  ];

  const initialState = {
    sortBy: [
      { desc: false, id: "id" },
      { desc: false, id: "description" }
    ],
    hiddenColumns: ["dishes", "id"]
  };

  return (
    <div>
      <button type="button" onClick={handleClick}>
        {buttonMode === "cancel" ? "Cancel" : "Apply"}
      </button>
      show good
      <Toggle value={showGood} onChange={() => setShowGood(!showGood)} />
      <Table
        data={tableData}
        columns={columns}
        initialState={initialState}
        withCellBorder
        withRowBorder
        withSorting
        withPagination
        rowProps={getRowProps}
      />
    </div>
  );
}

如果你需要保留applyStatus的切换逻辑,只需要新增对应的控制开关,把过滤判断加到useMemo里的对应位置即可,不要在渲染流程中直接修改state。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 19:09:18