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

NextUI Select组件异步API赋值selectedKeys时出现无效键错误

解决NextUI Select组件selectedKeys赋值异常问题

问题描述

异步API调用结果传给子组件后,NextUI的Input组件能正常接收props,但Select组件给selectedKeys赋值gender时出现报错:

Select: Keys "" passed to "selectedKeys" are not present in the collection.
后续字段也无法正常工作。

问题根源

  1. 初始值无效:API请求完成前,gender可能是undefined或空字符串,直接用new Set([gender])会把空字符串加入集合,而Select选项里没有对应key,触发报错。
  2. 状态未同步:子组件的genderValue仅在挂载时初始化一次,父组件传入的gender更新后,状态不会自动同步。
  3. 父组件数据管理错误:basicDetailsObj是普通变量,不是React状态,API返回数据后无法触发组件重渲染,子组件拿不到最新数据。

修复方案

1. 父组件:改用状态管理数据,正确触发重渲染

把basicDetailsObj改成React状态,用useEffect触发API请求,避免在渲染函数里直接调用接口导致无限渲染:

const PersonalInfo = () => {
  const [activeTab, setActiveTab] = useState("Basic Details");
  // 用状态存储数据,初始值设为null
  const [basicDetailsObj, setBasicDetailsObj] = useState<BasicDetailsType | null>(null);

  const handleGetProfile = () => {
    if(accessToken){
      const user: LoginDetails = use(getUserDetailsByToken(accessToken));
      const ProfileReq: ProfileType = {
        empid: user.Empid,
        profile: activeTab,
      };
      const result: getprofile201Type = use(getProfile(accessToken,ProfileReq));
      
      // 确认数据存在后更新状态
      if (activeTab === "Basic Details" && result?.getprofile201?.[0]) {
        setBasicDetailsObj(result.getprofile201[0]);
      }
    }
  };

  // 监听activeTab和accessToken变化,触发API请求
  useEffect(() => {
    handleGetProfile();
  }, [activeTab, accessToken]);

  const renderTabContent = () => {
    // 加载状态提示
    if (!basicDetailsObj) return <div>加载中...</div>;
    return <BasicDetails 
      firstName={basicDetailsObj.firstName}
      lastName={basicDetailsObj.lastName}
      gender={basicDetailsObj.gender}
    />;
  };

  return (
    <div className="mt-3 h-auto m-0 justify-center flex gap-3 flex-col">
      {renderTabContent()}
    </div>
  );
};

export default PersonalInfo;

2. 子组件:处理空值+同步父组件props更新

给gender设置默认值,用useEffect监听gender变化,同步更新选择状态,同时过滤无效值:

import React, { useEffect } from "react";
import { Input, Select, SelectItem } from "@nextui-org/react";

interface IBasicDetails {
  firstName: string;
  lastName: string;
  gender?: string; // 设为可选属性
}

const BasicDetails: React.FC<IBasicDetails> = ({
  firstName = "",
  lastName = "",
  gender = ""
}) => {
  // 初始值:如果gender有效就用它,否则用空集合
  const [genderValue, setGenderValue] = React.useState<Set<string>>(
    gender && ["Male", "Female", "Other"].includes(gender) ? new Set([gender]) : new Set()
  );

  // 监听gender变化,同步更新选择状态
  useEffect(() => {
    if (gender && ["Male", "Female", "Other"].includes(gender)) {
      setGenderValue(new Set([gender]));
    } else {
      setGenderValue(new Set()); // 无效值时清空选择
    }
  }, [gender]);

  return (
    <div className="mb-5 h-full m-0 justify-center ">
      <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-5 text-gray-600">
        {/* First Name */}
        <div className="flex flex-col">
          <Input
            type="text"
            id="firstname"
            value={firstName}
            disabled
            isRequired
            label="First Name"
            placeholder=" "
            labelPlacement="outside"
          />
        </div>
        {/* Last Name */}
        <div className="flex flex-col">
          <Input
            type="text"
            id="lastname"
            value={lastName}
            disabled
            isRequired
            label="Last Name"
            placeholder=" "
            labelPlacement="outside"
          />
        </div>
        {/* Gender */}
        <div className="flex flex-col">
          <Select
            labelPlacement="outside"
            label="Gender"
            placeholder="Select Gender"
            selectedKeys={genderValue}
            className="max-w-lg text-black font-bold"
            isRequired
            fullWidth
            onChange={(e) => setGenderValue(e.target.selectedKeys)} // 处理用户手动选择
          >
            <SelectItem key="Male" value="Male">
              Male
            </SelectItem>
            <SelectItem key="Female" value="Female">
              Female
            </SelectItem>
            <SelectItem key="Other" value="Other">
              Other
            </SelectItem>
          </Select>
        </div>
      </div>
    </div>
  );
};

export default BasicDetails;

核心修复点

  • 父组件用useState管理数据,确保API返回后触发重渲染,子组件能获取最新值。
  • 子组件通过useEffect监听props变化,同步更新选择状态,同时过滤无效值避免报错。
  • 给props设置默认值,防止API加载阶段出现undefined导致的异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 08:45:13