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

React中MultiSelect多选值分存不同数组的功能异常排查

问题修复:MultiSelect多选值按层级存入对应数组

需求说明

希望在MultiSelect组件中选择值后,将每个多选组件的选中值存入不同数组,默认数组为空,最终形成类似{1:[1,2],2:[2,3]}的结构。

现有代码问题

你提供的代码存在几个关键问题导致多选功能失效:

  • MultiSelect组件的value和onChange属性被注释,无法与父组件状态联动
  • 初始化选中值状态时逻辑错误,没有为每个层级的set分配空数组
  • 状态更新后的同步打印无法获取最新值
  • 两个输入控件(下拉选择框和数字输入框)绑定了同一个处理函数,逻辑混乱

修复方案

  1. 恢复MultiSelect的联动属性:取消value和onChange的注释,让组件能读取选中值并触发状态更新
  2. 修正状态初始化逻辑:在切换层级时,为每个set初始化空数组,确保结构正确
  3. 调整状态更新方式:修正handleMultiSelectChange中的对象嵌套更新逻辑,保证每个set的选中值正确存入对应位置
  4. 正确打印更新后的状态:使用useEffect监听状态变化,而非同步打印
  5. 优化列表key值:用setNumber作为列表key,避免index作为key引发的渲染异常

修正后的完整代码

import React, { useState, useEffect } from 'react';
import { fetchApprovalItemType, fetchAllStaff } from './data';

import Set from './set';
import MultiSelect from './MultiSelect';

const AddApprovalItems = () => {
  const [items, setItems] = useState([]);
  const [staffs, setStaff] = useState([]);
  const [approvalItemLevel, setApprovalItemLevel] = useState('');
  const [selectedOptions, setSelectedOptions] = useState({});
  const [sets, setSets] = useState([]);

  useEffect(() => {
    const fetchData = async () => {
      const item = await fetchApprovalItemType();
      setItems(item);
    };

    const fetchStaff = async () => {
      const staff = await fetchAllStaff();
      setStaff(staff);
    };

    fetchData();
    fetchStaff();
  }, []);

  // 监听选中值变化,打印最新状态
  useEffect(() => {
    console.log('最新选中值:', selectedOptions);
  }, [selectedOptions]);

  const handleApprovalLevelChange = (e) => {
    const level = parseInt(e.target.value);
    setApprovalItemLevel(level);

    // 创建对应数量的set
    const newSets = Array.from({ length: level }, (_, index) => index + 1);
    setSets(newSets);

    // 初始化当前层级的选中值:每个set对应空数组
    setSelectedOptions((prevOptions) => ({
      ...prevOptions,
      [level]: newSets.reduce((acc, num) => {
        acc[num] = [];
        return acc;
      }, {})
    }));
  };

  const handleMultiSelectChange = (selected, setNumber) => {
    setSelectedOptions((prevOptions) => ({
      ...prevOptions,
      [approvalItemLevel]: {
        ...prevOptions[approvalItemLevel],
        [setNumber]: selected.map(option => option.value),
      },
    }));
  };

  const onSubmit = (e) => {
    e.preventDefault();
    console.log('提交的选中值:', selectedOptions);
  };

  return (
    <div className="flex justify-center items-center lg:mt-[5%] mt-[20%]">
      <div className="card lg:w-1/2 w-[80%] rounded-[10px]">
        <div className="p-6">
          <div className="flex">
            <h4 className="mb-5 uppercase dark:text-gray-300">Add Home Ownership</h4>
          </div>

          <form className="px-10">
            <div className="mb-3">
              <label className="block mb-2 font-semibold" htmlFor="approvalItemLevel">
                Approval Item Type
              </label>
              <div>
                <select
                  id="approvalItemLevel"
                  className="form-select form-select-sm"
                  onChange={handleApprovalLevelChange}
                  value={approvalItemLevel}
                >
                  <option value="">Select Approval Item Level</option>
                  {items.map((it, idx) => (
                    <option key={idx} value={it}>{it}</option>
                  ))}
                </select>
              </div>
            </div>
            <div className="mb-3">
              <label className="block mb-2 font-semibold" htmlFor="approvalItemType">
                Approval Item level
              </label>
              <div>
                <input
                  type="number"
                  id="approvalItemType"
                  name="approvalItemType"
                  className="form-input w-full placeholder:text-gray-400"
                  onChange={handleApprovalLevelChange}
                  value={approvalItemLevel}
                />
              </div>
            </div>
            
            {/* 渲染生成的set */}
            <div className="mb-3">
              {sets.map((setNumber) => (
                <div key={setNumber}>
                  <Set />
                  <MultiSelect 
                    option={staffs.map((staff) => ({
                      label: staff.email,
                      value: staff.id,
                    }))}
                    value={selectedOptions[approvalItemLevel]?.[setNumber] || []}
                    onChange={(selected) => handleMultiSelectChange(selected, setNumber)}
                  />
                </div>
              ))}
            </div>

            <button type="submit" className="btn bg-primary/90 text-white hover:bg-primary" onClick={onSubmit}>
              Submit
            </button>
          </form>
        </div>
      </div>
    </div>
  );
};

export default AddApprovalItems;

关键修复点说明

  • 恢复MultiSelect的value和onChange属性,实现组件与父状态的双向绑定
  • 初始化selectedOptions时,通过reduce为每个set生成空数组,确保结构符合{层级: {set1: [], set2: []}}
  • 使用useEffect监听selectedOptions变化,确保打印的是最新状态
  • 用setNumber作为列表key,避免index作为key可能导致的组件渲染异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 16:14:54