Preact Signal修改对象属性值无效的问题咨询
Preact Signal 对象属性修改不生效问题解答
问题描述
编写了如下React+TypeScript代码,代码无报错,但siteRequest对象的数值始终未改变。疑问点:
siteRequest.value.SiteName = newText;语法是否错误?- Preact Signal 是否不支持普通对象(非数组)的属性修改?
- deepsignal 能否解决该问题?
import { signal } from '@preact/signals'; // ... const initalRequest: IRequest = { "SiteDisplayName": "Something", "SiteName": "", "SiteDescription": "", "SiteMembers": [], "SiteOwner": "", "Sitetype": SiteTypes.WithoutTeams, }; const siteRequest = signal(initalRequest); const onTextFieldChange = (ev: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, newText: string): void => { //console.log('onTextFieldChange', ev.currentTarget.id); switch (ev.currentTarget.id) { case "Name": siteRequest.value.SiteName = newText; break; // remove spaces .split(' ').join('') case "SiteDisplayName" : siteRequest.value.SiteDisplayName = newText; break; case "SiteDescription" : siteRequest.value.SiteDescription = newText; break; default:break; } // Case "" :siteRequest.value.SiteOwner = ""; }; return ( <section className={`${styles.createNoProjectSite} ${hasTeamsContext ? styles.teams : ''}`}> <h2>Well done, {escape(userDisplayName)}!</h2> <TextField id='Name' label="Site Name" value={siteRequest.value.SiteName} onChange={onTextFieldChange} /> <TextField id='SiteDisplayName' label="Site Display Name" value={siteRequest.value.SiteName} onChange={onTextFieldChange} /> <TextField id='SiteDescription' label="Site Description" value={siteRequest.value.SiteName} onChange={onTextFieldChange} multiline={true} /> <div>{siteRequest.value.SiteDescription}</div> <br /> <pre>{JSON.stringify(siteRequest.value, null, 2)}</pre> </section> );
解答
1. 语法与更新逻辑问题
你当前的写法siteRequest.value.SiteName = newText并非语法错误,但属于无效的更新方式。Preact的普通signal遵循不可变更新原则:它只会追踪value的整体替换操作,不会监听对象内部属性的修改。直接修改属性时,signal无法感知到变化,自然不会触发组件重渲染,也就看不到数值更新。
2. 普通Signal支持对象,但需正确更新
Preact Signal完全支持普通对象,但必须通过替换整个value来触发更新。正确的写法是使用扩展运算符创建新对象:
// 保持switch结构的正确写法 switch (ev.currentTarget.id) { case "Name": siteRequest.value = { ...siteRequest.value, SiteName: newText }; break; case "SiteDisplayName" : siteRequest.value = { ...siteRequest.value, SiteDisplayName: newText }; break; case "SiteDescription" : siteRequest.value = { ...siteRequest.value, SiteDescription: newText }; break; default:break; }
3. deepsignal可以解决直接修改属性的问题
deepsignal(来自@preact/signals-deep)专门用于支持深度可变更新,它会自动追踪对象内部属性的变化。使用deepsignal后,你原本直接修改属性的写法就能生效,无需改变更新逻辑:
import { deepsignal } from '@preact/signals-deep'; // ... const siteRequest = deepsignal(initalRequest); // 原onTextFieldChange函数无需修改,直接用siteRequest.value.SiteName = newText即可
额外注意:TextField绑定错误
你的代码中存在TextField的value绑定错误:
SiteDisplayName字段的value绑定成了siteRequest.value.SiteName,应该改为siteRequest.value.SiteDisplayNameSiteDescription字段的value同样绑定错误,需改为siteRequest.value.SiteDescription
这个错误会导致输入框显示内容不符合预期,建议一并修正。
内容的提问来源于stack exchange,提问作者Ofer Gal
相关产品推荐
相关产品推荐

