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

React中使用Material-UI表格点击排序功能失效问题求助

问题修复:React表格排序切换失效

错误原因分析

  • 直接修改原数组导致React无法检测更新:Array.sort()是原地修改数组,直接将修改后的原数组传给setData,React会认为数组引用未变化,不会触发重渲染。
  • useEffect中排序逻辑错误:先对初始空数组data排序,随后直接设置response.data,排序操作未生效,应先复制接口返回数据再排序。
  • 排序函数分支逻辑错误:sorting中使用两个独立if,修改order后第二个条件会立即触发,导致排序和状态来回切换,最终无变化。
  • 未区分数据类型排序:Age为数字类型,使用toLowerCase()会报错,需单独处理字符串与数字的排序逻辑。

修复后的完整代码

import "../App.css";
import { useEffect, useState } from "react";
import { styled } from "@mui/material/styles";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableCell, { tableCellClasses } from "@mui/material/TableCell";
import TableContainer from "@mui/material/TableContainer";
import TableHead from "@mui/material/TableHead";
import TableRow from "@mui/material/TableRow";
import Paper from "@mui/material/Paper";
import { Grid } from "@mui/material";
import axios from "axios";

const App = () => {
  const StyledTableCell = styled(TableCell)(() => ({
    [`&.${tableCellClasses.head}`]: {
      fontStyle: "normal",
      fontWeight: 600,
      fontSize: "16px",
      width: "fit-content",
      whiteSpace: "nowrap",
      lineHeight: "24px",
      cursor: "pointer"
    },
    [`&.${tableCellClasses.body}`]: {
      fontStyle: "normal",
      fontWeight: 600,
      fontSize: "16px",
      width: "fit-content",
      whiteSpace: "nowrap",
      overflow: "hidden",
      textOverflow: "ellipsis",
      lineHeight: "24px",
    },
  }));
  const StyledTableRow = styled(TableRow)(() => ({
    "&:nth-of-type(odd)": {
      fontStyle: "normal",
      fontWeight: 600,
      fontSize: "16px",
    },
  }));
  
  const [data, setData] = useState([]);
  const [order, setOrder] = useState('asc');
  const [sortCol, setSortCol] = useState('name');

  useEffect(() => {
    axios
      .get("https://someapiurl")
      .then((response) => {
        if(response.data?.length) {
          const sortedData = [...response.data].sort((a, b) => {
            if (typeof a.name === 'string') {
              return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
            }
            return 0;
          });
          setData(sortedData);
        } else {
          setData([]);
        }
      });
  }, []);

  const sorting = (col) => {
    const newOrder = sortCol === col ? (order === 'asc' ? 'dsc' : 'asc') : 'asc';
    setSortCol(col);
    setOrder(newOrder);

    const sorted = [...data].sort((a, b) => {
      if (typeof a[col] === 'string') {
        const valA = a[col].toLowerCase();
        const valB = b[col].toLowerCase();
        return newOrder === 'asc' ? valA.localeCompare(valB) : valB.localeCompare(valA);
      } else if (typeof a[col] === 'number') {
        return newOrder === 'asc' ? a[col] - b[col] : b[col] - a[col];
      }
      return 0;
    });
    setData(sorted);
  }

  return (
    <div className="container">
      <Grid
        xs={12}
        md={12}
        lg={12}
        container
      >
        <Paper>
          <TableContainer>
            <Table stickyHeader aria-label="sticky table">
              <TableHead>
                <TableRow>
                  <StyledTableCell align="left" onClick={() => sorting("name")}>
                    Name {sortCol === 'name' && (order === 'asc' ? '↑' : '↓')}
                  </StyledTableCell>
                  <StyledTableCell align="left" onClick={() => sorting("age")}>
                    Age {sortCol === 'age' && (order === 'asc' ? '↑' : '↓')}
                  </StyledTableCell>
                </TableRow>
              </TableHead>
              <TableBody>
                {data.map((row) => (
                  <StyledTableRow key={row.name}>
                    <StyledTableCell align="left">
                      {row.name}
                    </StyledTableCell>
                    <StyledTableCell align="left">
                      {row.age}
                    </StyledTableCell>
                  </StyledTableRow>
                ))}
              </TableBody>
            </Table>
          </TableContainer>
        </Paper>
      </Grid>
    </div>
  );
};

export default App;

关键修复点说明

  • 避免原地修改数组:每次排序用[...data]复制原数组,创建新引用,确保React能检测到数组变化。
  • 修正useEffect排序逻辑:先复制接口返回数据再排序,再更新状态。
  • 优化排序分支逻辑:记录当前排序列,点击同列切换顺序,不同列默认升序,避免状态来回切换。
  • 区分数据类型排序:字符串用localeCompare做自然排序,数字直接做数值比较,避免报错。
  • 增加排序状态提示:表头显示升降序箭头,提升用户体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 05:30:15