React实现可按所有表头排序的用户表格问题求助
多表头排序解决方案
现有问题分析
- 排序函数硬编码了
name字段,无法根据点击的表头动态切换排序目标 - 条件判断
if (order === "" || "asc")逻辑错误,"asc"为真值会导致永远进入第一个分支 - 未记录当前排序字段,无法区分是切换同一字段的排序顺序还是切换到新字段排序
修改步骤及代码
1. 在Home组件添加排序字段状态
添加sortKey状态跟踪当前排序的字段,初始值设为name:
const [sortKey, setSortKey] = useState("name");
2. 重构sortData函数,支持动态字段排序
修改排序逻辑,接收点击的字段名,处理不同类型字段的排序规则(字符串用localeCompare,日期用Date对象比较):
const sortData = (key) => { // 点击当前排序字段则切换顺序,点击新字段默认升序 const newOrder = sortKey === key ? (order === "asc" ? "dsc" : "asc") : "asc"; setSortKey(key); setOrder(newOrder); let sortedArr = [...newUserArr].sort((a, b) => { // 日期字段特殊处理,用原始值转Date比较 if (key === "birthday") { const dateA = new Date(a.birthday); const dateB = new Date(b.birthday); return newOrder === "asc" ? dateA - dateB : dateB - dateA; } // 字符串字段按localeCompare排序 return newOrder === "asc" ? a[key].localeCompare(b[key]) : b[key].localeCompare(a[key]); }); setNewUserArr(sortedArr); setOrdIcon(newOrder === "asc" ? arrowUp : arrowDown); };
3. 修改Table组件,传递点击的表头字段
修改th的点击事件,传递当前表头对应的字段名(与数据对象的key匹配):
{headerData.map((headerTable) => { const key = headerTable.toLowerCase(); return ( <th onClick={() => sortData(key)} id={"header-" + key} key={key} > {headerTable} <img src={ordIcon} id="arrow-img" alt="排序箭头" /> </th> ); })}
4. 完整修改后代码
Home组件关键部分
import { useState } from "react"; import Table from "./Table"; import arrowUp from "./path/to/arrow-up.png"; import arrowDown from "./path/to/arrow-down.png"; function Home() { const headerUser = ["Name", "Email", "Occupation", "Birthday"]; const [newUserArr, setNewUserArr] = useState([ { name: "Alice", email: "alice@example.com", occupation: "Engineer", birthday: "1990-01-01" }, { name: "Bob", email: "bob@example.com", occupation: "Designer", birthday: "1985-05-15" } ]); const [order, setOrder] = useState("asc"); const [ordIcon, setOrdIcon] = useState(arrowUp); const [sortKey, setSortKey] = useState("name"); const sortData = (key) => { const newOrder = sortKey === key ? (order === "asc" ? "dsc" : "asc") : "asc"; setSortKey(key); setOrder(newOrder); let sortedArr = [...newUserArr].sort((a, b) => { if (key === "birthday") { const dateA = new Date(a.birthday); const dateB = new Date(b.birthday); return newOrder === "asc" ? dateA - dateB : dateB - dateA; } return newOrder === "asc" ? a[key].localeCompare(b[key]) : b[key].localeCompare(a[key]); }); setNewUserArr(sortedArr); setOrdIcon(newOrder === "asc" ? arrowUp : arrowDown); }; return ( <div> <Table headerData={headerUser} bodyData={newUserArr} sortData={sortData} ordIcon={ordIcon} /> </div> ); } export default Home;
Table组件修改后
import { formatDate } from "../../utils/formatDate"; import "./table.css"; function Table(props) { const { headerData, bodyData, sortData, ordIcon} = props; return ( <div className="user-data"> <table className="user-table"> <thead> <tr className="data-th"> {headerData.map((headerTable) => { const key = headerTable.toLowerCase(); return ( <th onClick={() => sortData(key)} id={"header-" + key} key={key} > {headerTable} <img src={ordIcon} id="arrow-img" alt="排序箭头" /> </th> ); })} </tr> </thead> <tbody> {bodyData.map((item, index) => ( <tr className="data-tr" key={index}> <td>{item.name}</td> <td>{item.email}</td> <td>{item.occupation}</td> <td>{formatDate(item.birthday)}</td> </tr> ))} </tbody> </table> </div> ); } export default Table;
额外说明
- 给列表项添加
key属性避免React警告 - 日期排序使用原始的ISO格式字符串转
Date对象比较,确保排序准确性 - 点击同一表头切换排序顺序,点击新表头默认按升序排序
内容的提问来源于stack exchange,提问作者Dênis
相关产品推荐
相关产品推荐

