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
相关产品推荐
相关产品推荐

