切换Link下拉框时DropdownSection默认选项未正确设置问题
问题描述
我有一个Link下拉框,切换它会更新对应的DropdownSection组件(该组件包含不同的选项数组)。需求是:
- 切换到不同Link时,若对应选项数组长度大于1,
DropdownSection的默认选项设为第二个选项(跳过第一个“No Selection”选项),比如选择Link 2时应选中“Three”选项。
当前存在的问题:当手动选中DropdownSection的某个选项后,再切换Link下拉框,DropdownSection的选中项会变成空白。
初始状态:应用加载时,Link 1为默认选中项,DropdownSection默认选中“One”选项。
切换Link 2后的预期状态:DropdownSection默认选中“Three”选项。
示例代码(设置默认选项)
<DropdownSection label={linkOptions[0].text} options={link1Options} defaultOptionText={link1Options.length > 1 ? link1Options[1].text : "No Selection"} defaultOptionValue={link1Options.length > 1 ? link1Options[1].value : "0"} />
现有组件代码
App组件
const App = ({}) => { const linkOptions = [ { text: "Link 1", value: "1", }, { text: "Link 2", value: "2", }, { text: "Link 3", value: "3", }, ]; const [link, setLink] = useState(linkOptions[0].value); const link1Options = [ { text: "No Selection", value: "0", }, { text: "One", value: "1" }, { text: "Two", value: "2" }, ]; const link2Options = [ { text: "No Selection", value: "0", }, { text: "Three", value: "3" }, { text: "Four", value: "4" }, ]; const link3Options = [ { text: "No Selection", value: "0", }, { text: "Five", value: "5" }, { text: "Six", value: "6" }, ]; let linkDropdownSection = <></>; if (link === linkOptions[0].value) { linkDropdownSection = ( <DropdownSection label={linkOptions[0].text} options={link1Options} defaultOptionText={link1Options.length > 1 ? link1Options[1].text : "No Selection"} defaultOptionValue={link1Options.length > 1 ? link1Options[1].value : "0"} /> ); } else if (link === linkOptions[1].value) { linkDropdownSection = ( <DropdownSection label={linkOptions[1].text} options={link2Options} defaultOptionText={link2Options.length > 1 ? link2Options[1].text : "No Selection"} defaultOptionValue={link2Options.length > 1 ? link2Options[1].value : "0"} /> ); } else if (link === linkOptions[2].value) { linkDropdownSection = ( <DropdownSection label={linkOptions[2].text} options={link3Options} defaultOptionText={link3Options.length > 1 ? link3Options[1].text : "No Selection"} defaultOptionValue={link3Options.length > 1 ? link3Options[1].value : "0"} /> ); } // @ts-ignore: next-line - Ignore event parameter const onLinkSelect: DropdownProps["onOptionSelect"] = (event: any, data: any) => { setLink(data.optionValue); }; return ( <> <main> { <section> <Dropdown defaultValue={linkOptions[0].text} defaultSelectedOptions={[linkOptions[0].value]} onOptionSelect={onLinkSelect} > {linkOptions.map((option) => ( <Option key={`${optionId}-${option.value}`} value={option.value}> {option.text} </Option> ))} </Dropdown> {linkDropdownSection} </section> } </main> </> ); };
DropdownSection组件
const DropdownSection = ({ label, options, defaultOptionText, defaultOptionValue, }) => { const optionId = useId("option"); return ( <section> <div> <Label>{label}</Label> <Dropdown defaultValue={defaultOptionText} defaultSelectedOptions={[defaultOptionValue]} onOptionSelect={onContactSelect} > {options.map((option) => ( <FluentUIOption key={`${optionId}-${option.value}`} value={option.value}> {option.text} </FluentUIOption> ))} </Dropdown> </div> <Divider /> </section> ); };
问题原因
当前DropdownSection使用defaultValue和defaultSelectedOptions这两个非受控组件属性,它们仅在组件第一次挂载时生效。当用户手动选择选项后,组件内部会维护自身状态;切换Link时,虽然DropdownSection重新渲染,但React可能复用已有组件实例,导致内部状态未被重置,从而出现选中项空白的情况。
解决方案
将DropdownSection改为受控组件,由父组件(App)控制其选中状态,切换Link时强制重置选中值:
步骤1:在App组件中添加选中值状态
const App = ({}) => { // ... 原有代码 const [selectedOptionValue, setSelectedOptionValue] = useState(''); // 初始化默认选中值 useEffect(() => { const initialOptions = link1Options; setSelectedOptionValue(initialOptions.length > 1 ? initialOptions[1].value : "0"); }, []); // 切换Link时重置选中值 useEffect(() => { let currentOptions; if (link === linkOptions[0].value) { currentOptions = link1Options; } else if (link === linkOptions[1].value) { currentOptions = link2Options; } else { currentOptions = link3Options; } setSelectedOptionValue(currentOptions.length > 1 ? currentOptions[1].value : "0"); }, [link]); // ... 原有代码 };
步骤2:修改DropdownSection的props传递受控属性
替换App中渲染DropdownSection的逻辑,传递selectedValue和onOptionChange:
// Link 1对应的DropdownSection示例 linkDropdownSection = ( <DropdownSection label={linkOptions[0].text} options={link1Options} selectedValue={selectedOptionValue} onOptionChange={setSelectedOptionValue} /> ); // 其他Link对应的DropdownSection同理,移除default相关属性
步骤3:重构DropdownSection为受控模式
const DropdownSection = ({ label, options, selectedValue, onOptionChange, }) => { const optionId = useId("option"); const handleSelect = (event, data) => { onOptionChange(data.optionValue); }; // 匹配选中值对应的文本 const selectedText = options.find(opt => opt.value === selectedValue)?.text || "No Selection"; return ( <section> <div> <Label>{label}</Label> <Dropdown value={selectedText} selectedOptions={[selectedValue]} onOptionSelect={handleSelect} > {options.map((option) => ( <FluentUIOption key={`${optionId}-${option.value}`} value={option.value}> {option.text} </FluentUIOption> ))} </Dropdown> </div> <Divider /> </section> ); };
步骤4:优化App组件的DropdownSection渲染逻辑(可选)
用对象映射替代多个if-else,简化代码:
const linkOptionMap = { "1": { options: link1Options, label: linkOptions[0].text }, "2": { options: link2Options, label: linkOptions[1].text }, "3": { options: link3Options, label: linkOptions[2].text }, }; const currentLinkConfig = linkOptionMap[link]; const linkDropdownSection = ( <DropdownSection label={currentLinkConfig.label} options={currentLinkConfig.options} selectedValue={selectedOptionValue} onOptionChange={setSelectedOptionValue} /> );
内容的提问来源于stack exchange,提问作者tomtomdam
相关产品推荐
相关产品推荐

