如何在Fresh/Preact中将Signal默认值设为HTML Select选项默认值?
在Fresh/Preact中实现Select组件的默认值与选中状态同步
需求:
- 选中的选项值能在旁边实时显示
- 将Signal的默认值设为某个Option元素的默认值
尝试1:简单设置
import { signal } from "@preact/signals"; const pet = signal(undefined) function Pets() { return ( <> <select value={pet.value} onChange={e => pet.value = e.target.value} > <option selected value="dog">Dog</option> <option value="cat">Cat</option> <option value="hamster">Hamster</option> </select> {pet.value} </> ); } render(<Pets />, document.getElementById("app"));
问题:初始时无法获取默认选中的选项,且如果选项是动态生成的,无法直接指定Signal的默认值。
尝试2:循环生成选项并设置默认值
import { signal } from "@preact/signals"; const pet = signal(undefined) const arr = ['Dog', 'Cat', 'Hamster'] function Pets() { const options = [] for (const item of arr) { if (arr.indexOf(item) === 0){ options.push(<option selected value={item}>{item}</option>) pet.value = item } else { options.push(<option value={item}>{item}</option>) } } return ( <> <select value={pet.value} onChange={e => pet.value = e.target.value} > {options} </select> {pet.value} </> ); } render(<Pets />, document.getElementById("app"));
问题:Select元素冻结,无法选择其他选项。推测是代码在组件内部,每次渲染都会重置默认值。
尝试3:将循环移至组件外部
import { signal } from "@preact/signals"; const pet = signal(undefined) const arr = ['Dog', 'Cat', 'Hamster'] const options = [] for (const item of arr) { if (arr.indexOf(item) === 0){ options.push(<option selected value={item}>{item}</option>) pet.value = item } else { options.push(<option value={item}>{item}</option>) } } function Pets() { return ( <> <select value={pet.value} onChange={e => pet.value = e.target.value} > {options} </select> {pet.value} </> ); } render(<Pets />, document.getElementById("app"));
该方案解决了问题,但存在两个疑问:
- 为什么尝试2无法正常工作?原以为Signal只会更新文本而非重渲染整个组件;
- 检查结果发现没有选中的选项标记。
疑问解答
1. 尝试2失效的原因
Signal的更新确实会触发组件重渲染——当pet.value变化时,Pets组件会重新执行整个函数体。每次渲染时,循环都会重新生成所有Option,并且强制将第一个Option设为selected,同时把pet.value重置为第一个选项的值。这就导致用户选择其他选项时,组件立刻重渲染并把值改回初始状态,看起来像是Select被冻结了。
2. 为什么没有选中的选项标记
因为你同时给Select设置了value={pet.value},又给Option设置了selected属性,这两者会产生冲突。在Preact中,受控组件(通过value绑定状态的组件)会忽略Option上的selected属性,以绑定的状态值为准。虽然尝试3中pet.value被设为了第一个选项的值,Select会正确选中对应选项,但DOM里不会显示Option的selected属性,因为受控模式下由状态控制选中状态,而非Option的属性。
内容的提问来源于stack exchange,提问作者Ooker
相关产品推荐
相关产品推荐

