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

如何在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"));

该方案解决了问题,但存在两个疑问:

  1. 为什么尝试2无法正常工作?原以为Signal只会更新文本而非重渲染整个组件;
  2. 检查结果发现没有选中的选项标记。

疑问解答

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 05:17:01