MUI TableCell sortDirection属性不生效 表格行位置错乱问题
问题根因
你给TableCell加的sortDirection属性完全没用,这个是MUI Table提供的排序状态标记,仅用来给表头加排序箭头样式,不会自动控制行顺序。
行移位的核心原因有两点:
- JS对象本身不保证键的枚举顺序稳定:
react-cookie更新cookie时会重构存储对象,被更新的键会被移到对象键列表的末尾,直接遍历Object.keys(cookies)拿到的顺序自然会乱。 - 你写的
key={index}是错误用法:以数组索引作为列表key,一旦遍历顺序变化,React会错误复用DOM节点,加剧渲染异常。
修复方法
不要依赖cookies对象的原生键顺序渲染,单独维护一份固定的商品顺序列表,渲染时严格按照这个列表取数,同时修正列表key的写法;另外注意不要直接修改从cookie里拿到的原对象,更新时要做浅拷贝,避免不可变数据问题。
修复后完整代码
import { useState } from 'react'; import { useCookies } from 'react-cookie'; import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, Button, ButtonGroup } from '@mui/material'; export default function CartItemsTable() { const [cookies, setCookie, removeCookie] = useCookies(); // 维护固定的商品展示顺序,新增商品时把对应article字段存入该数组即可 const [cartItemOrder, setCartItemOrder] = useState(() => { // 初始化时取当前cookies里的键作为初始顺序 return Object.keys(cookies) }) function IncreaseQTY(article) { // 不直接修改原cookie对象,浅拷贝生成新对象 const newCookie = {...cookies[article]}; newCookie.qty++; setCookie(article, newCookie, { expires: new Date(Date.now() + 604800000), }); // 新加入购物车的商品,追加到顺序列表末尾 if (!cartItemOrder.includes(article)) { setCartItemOrder(prev => [...prev, article]) } } function DecreaseQTY(article) { const newCookie = {...cookies[article]}; newCookie.qty--; if (newCookie.qty === 0) { removeCookie(article); // 商品移除时同步从顺序列表中删除对应项 setCartItemOrder(prev => prev.filter(item => item !== article)) } else { setCookie(article, newCookie, { expires: new Date(Date.now() + 604800000), }); } } return ( <TableContainer component={Paper}> <Table sx={{ minWidth: 650 }} > <TableHead> <TableRow> <TableCell >Name</TableCell> <TableCell align="center">Code</TableCell> <TableCell align="center">Price</TableCell> <TableCell align="center">QTY</TableCell> <TableCell align="center">Total</TableCell> </TableRow> </TableHead> <TableBody> {/* 按照本地维护的固定顺序遍历,不再直接依赖Object.keys(cookies)的返回顺序 */} {cartItemOrder.map(function (articleKey) { const item = cookies[articleKey] // 过滤掉已经被删除的cookie项,避免渲染空数据 if (!item) return null return ( <TableRow key={articleKey} sx={{ "&:last-child td, &:last-child th": { border: 0 } }} > <TableCell component="th" scope="row"> {item.name} </TableCell> <TableCell align="center">{item.article}</TableCell> <TableCell align="center">{item.price}</TableCell> <TableCell align="center"> <ButtonGroup variant="contained" aria-label="outlined primary button group" > <Button onClick={() => { DecreaseQTY(item.article); }} > - </Button> <Button variant="text" disableRipple={true}> {item.qty} </Button> <Button onClick={() => { IncreaseQTY(item.article); }} > + </Button> </ButtonGroup> </TableCell> <TableCell align="center"> {item.qty * item.price} </TableCell> </TableRow> ); })} </TableBody> </Table> </TableContainer> ); }
改动说明
- 移除了无效的
sortDirection属性,该属性无任何自动控制排序/固定顺序的能力。 - 所有cookie更新操作都做了对象浅拷贝,避免直接修改原state导致的隐式bug。
- TableRow的key替换为商品唯一标识article,不会再因为顺序变化出现DOM复用错误。
内容的提问来源于stack exchange,提问作者Jeyhun085
相关产品推荐
相关产品推荐

