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

React项目中如何根据下拉框选中的省份筛选城市?

问题:城市下拉框未根据选中省份筛选

我正在开发一个Web应用,需要实现城市下拉框选项根据选中省份动态筛选的功能,但目前选择省份或城市时完全没有筛选效果。

以下是我尝试过但无效的代码实现:


Header组件(筛选逻辑写在此处)

export const Header = ({ data, isLoading, error }: HeaderProps) => {
  ...

  // 引入全局状态
  const {
    provinceDropdownFilter,
    cityDropdownFilter,
  } = useFilterStore();

  const filteredData = data.map((group) => group.equipments).flat();
  
  ...

  const handleDropdownFilterProvince = (
    e: React.ChangeEvent<HTMLSelectElement>
  ) => {
    useFilterStore.setState({ provinceDropdownFilter: e.target.value });

    // 根据选中的省份筛选数据
    const filteredCitiesSet = new Set<string>(
      filteredData
        .filter((item) => item.state === e.target.value)
        .map((item) => item.city)
    );

    const filteredCities = Array.from(filteredCitiesSet);

    useFilterStore.setState({ filteredCities: filteredCities });
    console.log("handle province dropdown cities", filteredCities);
  };

  const handleDropdownFilterCity = (
    e: React.ChangeEvent<HTMLSelectElement>
  ) => {
    useFilterStore.setState({ cityDropdownFilter: e.target.value });
  };

  ...

  return (
    <>
      ...
          <Dropdown
            data={data}
            value={manufacturerDropdownFilter}
            onChange={handleDropdownFilterManufacturer}
            filterType="manufacturer"
          />
          <Dropdown
            data={data}
            value={provinceDropdownFilter}
            onChange={handleDropdownFilterProvince}
            filterType="state"
          />
          <Dropdown
            data={data}
            value={cityDropdownFilter}
            onChange={handleDropdownFilterCity}
            filterType="city"
          />
     ...
    </>
  );
};

export const Dropdown: React.FC<DropdownProps> = ({
  data,
  onChange,
  value,
  filterType,
}) => {
  ...

  const filteredData = data.map((group) => group.equipments).flat();

  // 根据filterType筛选数据
  const filteredOptions = filteredData.filter((i) => {
    if (filterType === "manufacturer") {
      return i.manufacturer;
    }
    if (filterType === "state") {
      return i.state;
    }
    if (filterType === "city") {
      return i.city;
    }

    return false;
  });

  ...

  return (
    <>
      <Select
        aria-label="Select"
        placeholder={getCustomPlaceholder(filterType) as string}
        value={value}
        onChange={handleFilters}
      >
        {Array.from(uniqueValues)
          .sort()
          .map((value) => (
            <option key={value} value={value}>
              {value}
            </option>
          ))}
      </Select>
    </>
  );
};

Zustand状态仓库

const useFilterStore = create<FilterState>(
  zukeeper((set: any) => ({
    ...
    provinceDropdownFilter: "",
    cityDropdownFilter: "",
    filteredCities: [],
    ...
    setProvinceDropdownFilter: (value: string) =>
      set({ provinceDropdownFilter: value }),
    setCityDropdownFilter: (value: string) =>
      set({ cityDropdownFilter: value }),
    setFilteredCitiesFilter: (value: string[]) =>
      set({ filteredCities: value }),
    ...
  }))
);

问题分析

  1. Dropdown未使用筛选后的城市列表:你在Header中计算出了filteredCities并存入状态,但Dropdown组件完全忽略了这个状态,始终从原始data生成所有城市选项,没有应用省份筛选逻辑。
  2. Dropdown选项生成逻辑缺失:当前filteredOptions仅过滤存在对应字段的项,没有结合省份筛选条件,且代码中未明确uniqueValues的生成逻辑(即使存在,也未关联省份状态)。
  3. 状态同步问题:切换省份时未清空已选中的城市,可能导致选中的城市不在新的筛选列表中。

修复方案

1. 修改Dropdown组件,支持接收筛选后的选项

给Dropdown新增filteredOptions props,当为城市类型时优先使用传入的筛选结果:

export const Dropdown: React.FC<DropdownProps> = ({
  data,
  onChange,
  value,
  filterType,
  filteredOptions: propFilteredOptions, // 新增props
}) => {
  const filteredData = data.map((group) => group.equipments).flat();

  // 优先使用传入的筛选选项,否则从原始数据生成
  const rawOptions = propFilteredOptions ?? filteredData.map(item => {
    switch(filterType) {
      case "manufacturer": return item.manufacturer;
      case "state": return item.state;
      case "city": return item.city;
      default: return "";
    }
  }).filter(Boolean);

  // 去重并排序
  const uniqueValues = new Set(rawOptions);
  const sortedValues = Array.from(uniqueValues).sort();

  const handleFilters = (e: React.ChangeEvent<HTMLSelectElement>) => {
    onChange(e);
  };

  return (
    <Select
      aria-label="Select"
      placeholder={getCustomPlaceholder(filterType) as string}
      value={value}
      onChange={handleFilters}
    >
      {sortedValues.map((val) => (
        <option key={val} value={val}>
          {val}
        </option>
      ))}
    </Select>
  );
};

// 更新Props类型定义
interface DropdownProps {
  data: any; // 替换为你的实际数据类型
  onChange: (e: React.ChangeEvent<HTMLSelectElement>) => void;
  value: string;
  filterType: "manufacturer" | "state" | "city";
  filteredOptions?: string[]; // 新增可选props
}

2. 修改Header组件,传递筛选后的城市列表给Dropdown

引入filteredCities状态,并传给城市Dropdown:

export const Header = ({ data, isLoading, error }: HeaderProps) => {
  // 新增filteredCities状态
  const {
    provinceDropdownFilter,
    cityDropdownFilter,
    filteredCities,
  } = useFilterStore();

  const filteredData = data.map((group) => group.equipments).flat();
  
  const handleDropdownFilterProvince = (
    e: React.ChangeEvent<HTMLSelectElement>
  ) => {
    const selectedProvince = e.target.value;
    useFilterStore.setState({ 
      provinceDropdownFilter: selectedProvince,
      cityDropdownFilter: "" // 切换省份时清空城市选择
    });

    const filteredCitiesSet = new Set<string>(
      filteredData
        .filter((item) => item.state === selectedProvince)
        .map((item) => item.city)
    );

    useFilterStore.setState({ filteredCities: Array.from(filteredCitiesSet) });
  };

  const handleDropdownFilterCity = (
    e: React.ChangeEvent<HTMLSelectElement>
  ) => {
    useFilterStore.setState({ cityDropdownFilter: e.target.value });
  };

  return (
    <>
      ...
      <Dropdown
        data={data}
        value={manufacturerDropdownFilter}
        onChange={handleDropdownFilterManufacturer}
        filterType="manufacturer"
      />
      <Dropdown
        data={data}
        value={provinceDropdownFilter}
        onChange={handleDropdownFilterProvince}
        filterType="state"
      />
      <Dropdown
        data={data}
        value={cityDropdownFilter}
        onChange={handleDropdownFilterCity}
        filterType="city"
        filteredOptions={filteredCities} {/* 传入筛选后的城市 */}
      />
      ...
    </>
  );
};

3. 优化状态更新(可选)

封装Zustand的action,让状态更新逻辑更集中:

const useFilterStore = create<FilterState>(
  zukeeper((set) => ({
    provinceDropdownFilter: "",
    cityDropdownFilter: "",
    filteredCities: [],
    // 封装省份更新逻辑
    updateProvinceFilter: (value: string, rawData: any[]) => {
      const filteredData = rawData.map((group) => group.equipments).flat();
      const citySet = new Set<string>(
        filteredData
          .filter(item => item.state === value)
          .map(item => item.city)
      );
      set({
        provinceDropdownFilter: value,
        cityDropdownFilter: "",
        filteredCities: Array.from(citySet)
      });
    },
    setCityDropdownFilter: (value: string) =>
      set({ cityDropdownFilter: value }),
  }))
);

// Header中调用action
const handleDropdownFilterProvince = (
  e: React.ChangeEvent<HTMLSelectElement>
) => {
  useFilterStore.getState().updateProvinceFilter(e.target.value, data);
};

关键修复点总结

  • 城市Dropdown必须接收并使用从省份筛选出的城市列表,而非原始数据
  • 切换省份时清空城市选择,避免无效选项残留
  • 确保Dropdown的选项生成逻辑包含去重和排序

内容的提问来源于stack exchange,提问作者jrad09

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 07:05:21