如何在XState 5的onDone中正确使用Guard守卫?
XState 5中onDone的Guard配置问题解决
问题场景
我在编写XState 5状态机时遇到Guard不生效的问题:在checkingSession状态的invoke的onDone数组中,通过cond判断event.output.isAuthenticated的值,期望true时跳转至authenticated状态,false时跳转至notAuthenticated状态。但实际运行时,当event.output.isAuthenticated为false时,依然执行了authenticated状态的跳转和对应actions。
代码示例
checkingSession: { entry: () => console.log('Entered Checking status state'), invoke: { src: checkSession, input: ({context}) => ({ auth0Client: context.auth0Client }), onDone: [ { target: 'authenticated', cond: (_, event) => { console.log(`This user is authenticated ${event.output.isAuthenticated}`); return event.output?.isAuthenticated }, actions: ({context, event}) => { console.log("This does work "+event.output.isAuthenticated) context.user = event.output.user; context.isAuthenticated = event.output.isAuthenticated; } }, { target: 'notAuthenticated' } ], onError: { target: 'error', actions: assign({ error: (_, event) => event.error?.message || 'Failed to check session' }) } } }, notAuthenticated: { entry: () => console.log('Entered notAuthenticated state'), on: { LOGIN: 'authenticating' } }, authenticated: { entry: () => console.log('Entered authenticated state'), on: { LOGOUT: 'loggingOut', REFRESH: 'refreshing' } },
运行日志
Entered Checking status state index.js:23 Checking session... index.js:85 This does work false index.js:130 Entered authenticated state
问题原因与修复步骤
1. 确保Guard返回严格布尔值
你的Guard函数return event.output?.isAuthenticated可能因为isAuthenticated的类型问题(比如是字符串"false"、0等假值但非布尔false),导致返回值不符合预期。即使日志显示isAuthenticated为false,也可能存在类型隐式转换的问题。
修复:使用严格相等判断明确布尔值
cond: (_, event) => { console.log(`This user is authenticated ${event.output.isAuthenticated}`); // 严格匹配布尔类型的true return event.output?.isAuthenticated === true; }
2. 修正Context修改方式
你在action中直接修改context.user和context.isAuthenticated的写法不符合XState规范,会导致状态上下文不可预测,甚至间接影响Guard的判断逻辑。XState要求必须通过assign动作修改上下文:
修复:替换为assign动作
actions: assign({ user: (_, event) => event.output.user, isAuthenticated: (_, event) => event.output.isAuthenticated })
3. 为默认分支添加明确Guard(可选但推荐)
虽然XState会按顺序匹配onDone数组中的条目(第一个不匹配则执行第二个),但为了代码可读性和逻辑严谨性,建议给notAuthenticated分支添加明确的Guard:
{ target: 'notAuthenticated', cond: (_, event) => event.output?.isAuthenticated !== true }
修正后的完整代码片段
checkingSession: { entry: () => console.log('Entered Checking status state'), invoke: { src: checkSession, input: ({context}) => ({ auth0Client: context.auth0Client }), onDone: [ { target: 'authenticated', cond: (_, event) => { console.log(`This user is authenticated ${event.output.isAuthenticated}`); return event.output?.isAuthenticated === true; }, actions: assign({ user: (_, event) => event.output.user, isAuthenticated: (_, event) => event.output.isAuthenticated }) }, { target: 'notAuthenticated', cond: (_, event) => event.output?.isAuthenticated !== true } ], onError: { target: 'error', actions: assign({ error: (_, event) => event.error?.message || 'Failed to check session' }) } } }, notAuthenticated: { entry: () => console.log('Entered notAuthenticated state'), on: { LOGIN: 'authenticating' } }, authenticated: { entry: () => console.log('Entered authenticated state'), on: { LOGOUT: 'loggingOut', REFRESH: 'refreshing' } },
内容的提问来源于stack exchange,提问作者Jackie
相关产品推荐
相关产品推荐

