如何在XState状态机中始终加载Feature Flag至上下文?
解决XState状态机Hydrate时Feature Flag未加载的问题
要实现无论状态机初始化还是从保存状态恢复(hydrate)时都能加载Feature Flag并更新上下文,你可以通过以下几种方案解决根级invoke仅执行一次的问题:
方案1:事件驱动的可复用加载服务
将Feature Flag加载逻辑封装为可复用服务,同时保留根级初始化加载,并添加全局事件触发重新加载,确保hydrate后可以手动触发:
- 封装加载服务
const loadFeatureFlagsService = async () => { return await featureFlagService.load(); };
- 更新状态机配置
const stateMachine = createStateMachine({ id: 'state-machine', context: { featureFlagEvaluations: {} }, // 首次初始化时自动加载 invoke: { src: loadFeatureFlagsService, onDone: { actions: assign((_context, event) => ({ featureFlagEvaluations: event.data })) } }, // 添加全局事件,用于hydrate后手动触发加载 on: { LOAD_FEATURE_FLAGS: { invoke: { src: loadFeatureFlagsService, onDone: { actions: assign((_context, event) => ({ featureFlagEvaluations: event.data })) } } } }, states: { create: { /* ... */ }, retrieve: { /* ... */ } } });
- Hydrate后触发加载
// 从存储恢复状态 const savedState = JSON.parse(localStorage.getItem('stateMachineState')); // 启动状态机并传入保存的状态 const service = interpret(stateMachine).start(savedState); // 发送事件触发Feature Flag加载 service.send('LOAD_FEATURE_FLAGS');
这个方案既支持首次自动加载,也能在hydrate后手动触发,还支持后续需要动态刷新Feature Flag的场景(比如用户切换环境)。
方案2:外部预加载后初始化状态机
如果不需要动态刷新Feature Flag,可以将加载逻辑放在状态机外部,确保每次启动(包括hydrate)都先加载Flag,再初始化状态机:
// 预加载Feature Flag const preloadFeatureFlags = async () => { return await featureFlagService.load(); }; // 初始化状态机函数 const initStateMachine = async () => { const flags = await preloadFeatureFlags(); // 从存储恢复状态 const savedState = JSON.parse(localStorage.getItem('stateMachineState')); // 合并保存的上下文与新加载的Flag const mergedContext = { ...savedState?.context, featureFlagEvaluations: flags }; // 启动状态机 const service = interpret( stateMachine.withContext(mergedContext) ).start(savedState?.value); return service; }; // 调用初始化 initStateMachine();
这种方式更简单直接,完全绕过状态机内部的invoke限制,适合不需要动态更新Flag的场景。
方案3:异步Entry动作(XState v4.30+)
如果你的XState版本在v4.30及以上,可以使用异步entry动作,结合手动触发事件实现重复加载:
const stateMachine = createStateMachine({ id: 'state-machine', context: { featureFlagEvaluations: {} }, // 首次启动时执行异步加载 entry: async (context, event) => { const flags = await featureFlagService.load(); assign({ featureFlagEvaluations: flags })(context, event); }, // 添加事件支持手动刷新 on: { RELOAD_FEATURE_FLAGS: { actions: async (context, event) => { const flags = await featureFlagService.load(); assign({ featureFlagEvaluations: flags })(context, event); } } }, states: { create: { /* ... */ }, retrieve: { /* ... */ } } });
Hydrate后同样需要发送RELOAD_FEATURE_FLAGS事件触发加载。
内容的提问来源于stack exchange,提问作者Guilherme Gambeti
相关产品推荐
相关产品推荐

