我正在使用 Fresh/Preact。在 HTML 选择元素中,我想要两件事:
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"));
最初没有获得默认选择的选项。生成选项后,我无法指定信号的默认值。 游乐场
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"));
选择元素冻结,我无法选择其他选项。 游乐场
我认为这是因为代码位于组件内部,所以每次渲染时都会重置默认值。
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"));
这解决了问题。尽管如此,它仍然给我留下了两个未解决的问题:
我认为这是因为代码位于组件内部,所以每次渲染时都会重置默认值。
不,问题是您跳过了我的评论中相当关键的部分(因此存在基本的渲染缺陷):您将
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 属性是相关的,但最终是两个不同的东西。