如何在React中实现按retail_rate高低排序的运费筛选按钮
在React的USPSItems组件中实现按运费高低排序的功能
要实现按retail_rate字段排序的功能,你可以通过以下步骤修改组件:
1. 添加排序状态
在组件内部新增状态记录当前排序方向:
const [sortDirection, setSortDirection] = useState<'asc' | 'desc' | null>(null);
2. 生成排序后的运费列表
用useMemo缓存排序结果,避免不必要的重复计算:
const sortedShipmentOptions = useMemo(() => { if (!shipmentOptions) return []; // 复制原数组避免修改传入的props const sorted = [...shipmentOptions]; switch (sortDirection) { case 'asc': sorted.sort((a, b) => parseFloat(a.retail_rate) - parseFloat(b.retail_rate)); break; case 'desc': sorted.sort((a, b) => parseFloat(b.retail_rate) - parseFloat(a.retail_rate)); break; default: // 默认保持原顺序 break; } return sorted; }, [shipmentOptions, sortDirection]);
注意:
retail_rate是字符串格式,排序前需要转成数值类型。
3. 添加排序控制按钮
在运费列表容器上方添加两个按钮切换排序方向:
<div style={{ marginBottom: 16, display: 'flex', gap: 8 }}> <button onClick={() => setSortDirection('asc')} style={{ padding: '4px 12px', cursor: 'pointer' }} > 从低到高 </button> <button onClick={() => setSortDirection('desc')} style={{ padding: '4px 12px', cursor: 'pointer' }} > 从高到低 </button> </div>
可以替换成项目内的样式组件,保持UI风格统一。
4. 修复选中项逻辑(关键)
原组件用数组索引作为选中标识,排序后索引会失效,建议改用ShipmentRate的唯一属性(比如id)保存选中项:
// 替换原selectedItem状态 const [selectedRateId, setSelectedRateId] = useState<string | null>(null); // 修改点击事件处理函数 const handlePress = (rate: ShipmentRate) => { setSelectedRateId(rate.id); // 确保ShipmentRate类型包含id字段,无则替换为其他唯一标识 setSelectedRate(rate); setIsSelected(true); }; // 修改选中状态判断逻辑 isSelected={rate.id === selectedRateId}
完整修改后的组件代码
type Props = { shipmentOptions: ShipmentRate[]; isSelected?: boolean; setIsSelected?: Dispatch<SetStateAction<boolean>>; }; const USPSItems = ({ shipmentOptions, setIsSelected }: Props) => { const setSelectedRate = useShipmentRateStore( (state) => state.setSelectedRate ); const [sortDirection, setSortDirection] = useState<'asc' | 'desc' | null>(null); const [selectedRateId, setSelectedRateId] = useState<string | null>(null); const sortedShipmentOptions = useMemo(() => { if (!shipmentOptions) return []; const sorted = [...shipmentOptions]; switch (sortDirection) { case 'asc': sorted.sort((a, b) => parseFloat(a.retail_rate) - parseFloat(b.retail_rate)); break; case 'desc': sorted.sort((a, b) => parseFloat(b.retail_rate) - parseFloat(a.retail_rate)); break; default: break; } return sorted; }, [shipmentOptions, sortDirection]); const handlePress = (rate: ShipmentRate) => { setSelectedRateId(rate.id); setSelectedRate(rate); setIsSelected(true); }; return ( <> {/* 排序按钮区域 */} <div style={{ marginBottom: 16, display: 'flex', gap: 8 }}> <button onClick={() => setSortDirection('asc')} style={{ padding: '4px 12px', cursor: 'pointer' }} > 从低到高 </button> <button onClick={() => setSortDirection('desc')} style={{ padding: '4px 12px', cursor: 'pointer' }} > 从高到低 </button> </div> <ShipmentRatesContainer> {sortedShipmentOptions.map((rate: ShipmentRate) => ( <ClickableItem key={rate.id} onClick={() => handlePress(rate)}> <PackagesActiveItem isSelected={rate.id === selectedRateId} > <PackagesItemIcon> <SVGCustomIcon name="USPSLogo" /> </PackagesItemIcon> <div style={{ display: "flex", flexDirection: "column" }}> <PackagesItemLocation>{rate.carrier}</PackagesItemLocation> <PackagesItemService>{rate.service}</PackagesItemService> </div> <PackagesItemRight> <PackagesItemRightText> ${rate.retail_rate} </PackagesItemRightText> </PackagesItemRight> <USPSItemBottomText> Estimated to arrive{" "} {rate.est_delivery_days ? "in " + rate.est_delivery_days + " business days" : "within the next day"} </USPSItemBottomText> </PackagesActiveItem> </ClickableItem> ))} </ShipmentRatesContainer> </> ); };
注意事项
- 如果
ShipmentRate没有id字段,可以用retail_rate+service的组合作为唯一标识,或者要求后端返回唯一ID。 - 排序按钮的样式可根据项目UI规范替换为自定义组件。
- 使用
useMemo缓存排序结果是为了优化性能,避免每次渲染重复排序数组。
内容的提问来源于stack exchange,提问作者Julia Schafer
相关产品推荐
相关产品推荐

