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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 04:10:29