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.
后续字段也无法正常工作。
问题根源
- 初始值无效:API请求完成前,
gender可能是undefined或空字符串,直接用new Set([gender])会把空字符串加入集合,而Select选项里没有对应key,触发报错。 - 状态未同步:子组件的
genderValue仅在挂载时初始化一次,父组件传入的gender更新后,状态不会自动同步。 - 父组件数据管理错误:
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
相关产品推荐
相关产品推荐

