如何将信号的默认值设置为 HTML select 元素中选项元素的默认值?

问题描述 投票:0回答:1

我正在使用 Fresh/Preact。在 HTML 选择元素中,我想要两件事:

  • 所选选项的值随后显示为
  • 信号的默认值是选项元素的默认值

尝试 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"));

最初没有获得默认选择的选项。生成选项后,我无法指定信号的默认值。 游乐场

尝试 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"));

选择元素冻结,我无法选择其他选项。 游乐场

我认为这是因为代码位于组件内部,所以每次渲染时都会重置默认值。

尝试 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 不起作用?根据我的理解,信号不会重新渲染整个组件,而只会重新渲染文本。
  • 检查结果,我发现没有选定的选项
drop-down-menu signals preact preact-signal
1个回答
0
投票

我认为这是因为代码位于组件内部,所以每次渲染时都会重置默认值。

不,问题是您跳过了我的评论中相当关键的部分(因此存在基本的渲染缺陷):您将

pet.value
设置为每次重新渲染时的第一项。重新渲染组件后,您将再次设置它。这就是为什么我们需要
if (typeof pet.value == 'undefined')
,我们仅在这是第一次运行且该值尚未定义时才设置该值。在后续运行中,我们会跳过此操作。

以下是如何实现这一目标:

import { signal } from "@preact/signals";

const pet = signal(undefined)
const arr = ['Dog', 'Cat', 'Hamster'] 

function Pets() {
  const options = arr.map((item, idx) => {
    if (typeof pet.value == 'undefined' && idx == 0) pet.value = item;
    return <option selected={pet.value == item} 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"));

根据我的理解,信号不会重新渲染整个组件,而只会重新渲染文本。

信号可以跳过重新渲染,但在你的情况下不行。您正在循环(和组件)内访问信号,因此在信号更改时,您的组件必须重新渲染。此外,对于您的 API(生成一系列选项,其中一个带有

selected
),每次信号值发生变化时都必须运行。根本没有办法解决这个问题。

检查结果,我发现没有选定的选项

Preact 设置属性,而不是属性。在 Firefox 中,您可以右键单击 DOM 元素并选择“显示 DOM 属性”以获取完整的读数,在此您将看到

selected: true
。我确信 Chrome 有某种等效的东西。

DOM 属性和 HTML 属性是相关的,但最终是两个不同的东西。

© www.soinside.com 2019 - 2024. All rights reserved.