字段数据类型
input输入控件的value永远是字符串,而状态中的数据往往是number、boolean等类型。如果直接绑定,输入'123'会把数字类型的123覆盖成字符串,污染状态数据。
useField内置了类型驱动转换机制:以状态值的原始类型为依据,自动将输入值转换为对应类型后写入状态,反之亦然。
const { useField } = createStore({ count: 1 })
const countField = useField('count')
<input {...countField} /> // 输入 '123' -> 状态写入 123 (number)默认转换逻辑
类型转换逻辑由toState和fromState的默认实现进行,无需任何配置。
写入转换(defaultToState):input输入值 → 状态值
| 状态类型 | 输入值 | 写入结果 |
|---|---|---|
number | '123' / '12.5' | 123 / 12.5 |
number | 'abc' / ''(转换为NaN) | 0 |
boolean | 'true' / 'false' | true / false |
boolean | 其他值 | Boolean(输入值),如'是'→true、''→false |
string | 任意(含'0123'、'true') | 原样保持字符串,不做类型猜测 |
显示转换(defaultFromState):状态值 → input显示值
| 状态值 | 显示为 |
|---|---|
undefined / null / NaN | 空字符串''(checkbox 则checked: false) |
| 其他一切值 | 原样返回 |
上例中:
Age是number:输入'20'写入20,清空或输入非数字写入0。Vip是boolean:checkbox 直接以checked读写true/false。ZipCode是string:输入'075000'保持字符串,不会因像数字而被转为75000。Nickname初始为undefined:见下节空值推断。
类型依据是状态值本身
默认转换不猜测输入内容,只以状态值的typeof为依据。因此string状态的'0123'、'true'都不会被转成数字或布尔——这正是类型驱动转换与「启发式猜测输入内容」的本质区别。
空值推断
当状态值为空值(undefined / null / NaN)时,没有类型依据可循,此时按输入控件的类型推断:
| 控件类型 | 推断类型 | 首次输入写入 |
|---|---|---|
checkbox | boolean | checked值(true/false) |
number / range | number | 转换后的数字 |
其余(text / textarea / select / radio...) | string | 原样字符串 |
类型一经写入状态即自锁定,后续输入按状态类型转换,不再依赖控件推断。
重载 toState
通过options.toState可以整体替换默认的写入转换(不是叠加):
const fieldPrice = useField("order.price",{
toState:(value)=>{ // value 为 input 原始值
const num = Number(String(value).replace(/,/g,''))
return isNaN(num) ? 0 : num // 返回值写入状态
}
})value是未经任何转换的原始值(字符串或 checkbox 的boolean)。- 可选第二参数
{ path, part, stateValue, event }:stateValue为当前状态值,event为原始事件。 - 返回值直接写入状态。
重载 fromState
通过options.fromState可以整体替换默认的显示转换(状态值 → input显示值):
const fieldVip = useField("user.vip",{
fromState:(value)=> value===true ? '是' : '否'
})- 返回
undefined时保留原值(退出转换),适合只想拦截部分值的场景。
fromState通常与toState配对使用,实现「状态保存原始类型、界面显示友好内容」的双向映射:
上例中状态里始终保存着vip: true(boolean)与level: 2(number),而界面上显示与输入的是是/否、青铜/白银/黄金。
与 useForm 的转换是两套体系
useField的toState/fromState作用于hook 生成的绑定对象;useForm的同名配置作用于Form组件内部的 DOM 扫描体系(data-field原生表单元素)。二者相互独立,混用时各自生效于各自的绑定方式。