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

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.SiteDisplayName
  • SiteDescription字段的value同样绑定错误,需改为siteRequest.value.SiteDescription
    这个错误会导致输入框显示内容不符合预期,建议一并修正。

内容的提问来源于stack exchange,提问作者Ofer Gal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 07:32:08