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

React TypeScript级联选择组件搜索后选项加载异常求助

搜索后级联Select组件仅显示单个值,无法生成完整选项列表的问题修复

问题分析

非搜索模式下,父级Select选择后能正确生成子级的去重选项列表,级联逻辑正常;但触发搜索功能后,仅展示搜索结果中的单个对应值,后续Select组件没有生成完整的可用选项列表。核心原因是搜索分支的逻辑只做了数据过滤,没有为后续级联Select生成并更新对应的选项数据源。

修复方案

  1. 搜索完成后,基于过滤后的数据集,为每个后续级联Select生成去重选项并更新对应状态
  2. 清理Select组件中冗余的状态监听逻辑,避免重复触发更新导致的状态混乱
  3. 在Select组件中对选项列表做去重处理,避免重复渲染MenuItem

修改后的代码

Select组件

// Select component
import React, { useEffect, useId, useState } from "react"
import _ from "lodash"
import { FormControl, Select, InputLabel, MenuItem, SelectChangeEvent } from "@mui/material"
import ISelect from "@/types/select"

const SelectComponent: React.FC<ISelect> = (props) => {
  const { val, label, keyVal, dataList, onChangeVal } = props
  const [data, setData] = useState<any[]>([])
  const [value, setVal] = useState<any>(val || "")
  const id = useId()

  // 监听外部传入值更新本地选中状态
  useEffect(() => {
    if (val !== undefined) {
      setVal(val)
    }
  }, [val])

  // 根据数据源和字段生成去重的选项列表
  useEffect(() => {
    if (keyVal && dataList && dataList.length > 0) {
      const mappedData = _.map(dataList, keyVal)
      const uniqueData = _.uniq(mappedData)
      setData(uniqueData)
    } else {
      setData([])
    }
  }, [keyVal, dataList])

  // 选项只有一个时自动选中
  useEffect(() => {
    if (keyVal && data.length === 1 && onChangeVal) {
      const autoSelectVal = data[0]
      setVal(autoSelectVal)
      onChangeVal(keyVal, autoSelectVal)
    }
  }, [data, keyVal, onChangeVal])

  const handleChange = (e: SelectChangeEvent) => {
    const _val = e.target.value
    setVal(_val)
    onChangeVal?.(keyVal, _val)
  }

  return (
    <FormControl color="info" sx={{ minWidth: 100, fontSize: 13 }} size="small" fullWidth>
      <InputLabel>{label}</InputLabel>
      <Select
        onChange={handleChange}
        value={value}
        disabled={data.length === 0}
        label={label}
      >
        {data.map((d, i) => (
          <MenuItem key={`${keyVal}_${id}_${i}`} value={d}>
            {d}
          </MenuItem>
        ))}
      </Select>
    </FormControl>
  )
}

export default SelectComponent

过滤器与值处理函数

const onChangeVal = (type: string, val: any) => {
  const _filterData = _(sensitivity)
  const currentData = data || {}
  let _filters = {}
  let _unique: null | string = null
  let setItem: any

  switch (type) {
    case "year":
      _unique = "Type"
      setItem = setType
      _filters = isSearch ? { ...currentData } : { year: val }
      break
    case "Type":
      _unique = "Groupings"
      setItem = setGrouping
      _filters = isSearch ? { ...currentData } : { year: currentData.year, Type: val }
      break
    case "Groupings":
      _unique = "Region"
      setItem = setRegion
      _filters = isSearch ? { ...currentData } : { year: currentData.year, Type: currentData.Type, Groupings: val }
      break
    case "Region":
      _unique = "Type5"
      setItem = setType5
      _filters = isSearch ? { ...currentData } : { year: currentData.year, Type: currentData.Type, Groupings: currentData.Groupings, Region: val }
      break
    case "Type5":
      _unique = "Type4"
      setItem = setType4
      _filters = isSearch ? { ...currentData } : { year: currentData.year, Type: currentData.Type, Groupings: currentData.Groupings, Region: currentData.Region, Type5: val }
      break
    case "Type4":
      _unique = "Type3"
      setItem = setType3
      _filters = isSearch ? { ...currentData } : { year: currentData.year, Type: currentData.Type, Groupings: currentData.Groupings, Region: currentData.Region, Type5: currentData.Type5, Type4: val }
      break
    case "Type3":
      _unique = "Type2"
      setItem = setType2
      _filters = isSearch ? { ...currentData } : { year: currentData.year, Type: currentData.Type, Groupings: currentData.Groupings, Region: currentData.Region, Type5: currentData.Type5, Type4: currentData.Type4, Type3: val }
      break
    case "Type2":
      _filters = isSearch ? { ...currentData } : { year: currentData.year, Type: currentData.Type, Groupings: currentData.Groupings, Region: currentData.Region, Type5: currentData.Type5, Type4: currentData.Type4, Type3: currentData.Type3, Type2: val }
      setIsSearch(false)
      break
    case "Search":
      resetData()
      _filters = { ...val }
      setIsSearch(true)
      const filteredData = _filterData.filter(_filters).value()
      
      // 为后续所有级联Select生成去重选项并更新状态
      setType(_.uniqBy(filteredData, "Type"))
      setGrouping(_.uniqBy(filteredData, "Groupings"))
      setRegion(_.uniqBy(filteredData, "Region"))
      setType5(_.uniqBy(filteredData, "Type5"))
      setType4(_.uniqBy(filteredData, "Type4"))
      setType3(_.uniqBy(filteredData, "Type3"))
      setType2(_.uniqBy(filteredData, "Type2"))

      // 如果过滤后有数据,自动填充第一个结果到表单
      if (filteredData.length > 0) {
        setData({
          year: filteredData[0].year,
          Type: filteredData[0].Type,
          Groupings: filteredData[0].Groupings,
          Region: filteredData[0].Region,
          Type5: filteredData[0].Type5,
          Type4: filteredData[0].Type4,
          Type3: filteredData[0].Type3,
          Type2: filteredData[0].Type2
        })
      }
      break
  }

  if (_unique && typeof setItem === "function") {
    const _groupData = _filterData.filter(_filters).uniqBy(_unique).value()
    setItem(_groupData)
  }

  if (type !== "Search") {
    setData({ ...currentData, ..._filters })
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 21:54:55