XState嵌套状态的上下文数据怎么更新会报undefined错误?
我在用XState做表单验证时,定义了并行状态机包含form和validation两个状态。当尝试更新form.name字段时,控制台报错”Cannot set property ‘name’ of undefined”。已经用assign设置过初始上下文了,这是为什么?
机器配置是这样的:
{
context: {
form: {}
},
states: {
form: { ... },
validation: { ... }
}
}
我用send({ type: 'UPDATE', field: 'name', value: 'test' }),然后在action里写:
assign({
form: (ctx) => ({ ...ctx.form, [event.field]: event.value })
})
但执行到[event.field]赋值时就报错了,是不是嵌套状态的上下文访问方式有问题?试过给form加默认值还是不行...
context里定义了form是一个空对象,但在状态机运行时,如果form没有明确的默认值,assign操作可能会尝试访问一个未定义的路径,从而报错。具体来说,问题出在你的
assign表达式里:这里的
ctx.form在某些情况下可能是undefined,尤其是在状态机的状态切换或者上下文被部分覆盖时。虽然你提到已经用assign设置了初始上下文,但如果form的初始化不够明确,仍然会导致这个问题。解决方法很简单,确保
form的初始值是一个明确的对象,而不是空对象{}。你可以这样改:如果你不想为每个字段都写死默认值,可以用一个函数来动态初始化:
另外,
event对象在assign的回调函数中是不可直接访问的,你需要通过第二个参数传入。所以完整的assign应该是这样的:总结一下,问题的核心就是
ctx.form可能是undefined,你需要在更新之前确保它的存在。服务端开发的时候我们也经常遇到类似的坑,尤其是处理嵌套数据结构时,一定要确保每一层都有默认值或者做非空检查,不然很容易踩坑。希望这个回答能帮你解决问题。
event没传进去,action 里根本拿不到event.field。assign 的函数签名是(context, event) => {},你只写了 ctx,event 就 undefined 了,解构的时候自然崩。而且你写的是
{ ...ctx.form, [event.field]: event.value },这其实是把form对象的字段更新成平的结构了,比如你 expect 更新后是form: { name: 'test' },但按你这写法逻辑是对的,前提得能拿到 event。正确的写法得把 event 参数加上,同时确保 assign 正确接收两个参数。
代码放这了:
然后你发事件得带 field 和 value:
send({ type: 'UPDATE', field: 'name', value: 'test' })
另外确认你的状态机最外层 context 确实初始化了 form,不能只是声明空对象但没赋初始值。最好直接给默认值:
或者至少
{ form: {} }也行,但必须存在,不然 ctx.form 是 undefined,展开也会报错。还有一个隐藏坑:如果你用的是并行状态(parallel),确保你这个 action 是在正确状态节点里触发的,别被其他状态覆盖了 context。
先按这个改,大概率是 event 没接导致的 undefined。