我正在尝试使用Firebase持久化状态。我目前正在使用一个'saveState'功能,它可以很好地将最新状态保存到Firebase。
现在我希望能够根据Firebase中最近保存的状态初始化状态机。在下面的代码中,我试图使用我的"loadState"函数为Xstate提供一个配置对象。它当前返回一个promise,其中包含正确的状态配置。
下面是我的saveState代码:
//This function works fine.
function saveState(current, id){
let transactionJSON = serialize(current);
transactionJSON['createdOn'] = new Date();
return firebase.saveTransactionState({transactionJSON, transactionId:id});
}
这是我的'loadState'函数,它从Firebase返回一个承诺,其中包含正确的配置信息。
function loadState(id){
return firebase.getTransactionState({transactionId:id}).then(function(querySnapshot) {
return querySnapshot.docs.map(doc => deserialize({...doc.data()}) );
});
};
现在我的问题是试图用上面的'loadState'函数加载Xstate。这里我试图使用一个useMachine React钩子:
const [current, send] = useMachine(transactionMachine,{
state: () => loadState(id), //Trying to do something like this, but it doesn't seem to work.
actions:{
save: () => saveState(current, id),
},
});
TypeError: Cannot read property 'data' of undefined"我认为这是因为promise还没有解决,导致试图读取未定义的值。
这是可能的还是我做错了?
我对这一切都很陌生,任何指导都会很感激。谢谢你。
我想你可以使用useEffect
来更新你的状态机。
如何在状态机内调用取?
import { Machine, assign } from 'xstate';
const yourMachine = Machine({
id: 'yourStateMachine',
initial: 'fetching',
context: {
values: {
id: '', // likely need a state to initialize this value before fetching
apiDat: {}
},
},
states: {
fetching: {
invoke: {
src: ({values}) => firebase
.getTransactionState({ transactionId: values.id })
.then(function(querySnapshot) {
return querySnapshot.docs.map(
doc => deserialize({...doc.data()})
);
}),
onDone: { target: 'resolving', actions: 'cacheApiDat' },
onError: { target: 'error.fetchFailed' },
}
},
resolving: {
initial: 'delay',
states: {
delay: {
after: {
750: 'resolve'
},
},
resolve: {
always: [
{ cond: 'isSuccess', target: '#yourStateMachine.idle' },
{ cond: 'isUnauthorized', target: '#yourStateMachine.error.auth' },
],
}
},
},
error: {
states: {
fetchFailed: {
type: 'final',
},
auth: {
type: 'final',
}
}
},
idle: {
},
}
},{
actions: {
cacheApiDat: assign({ values: ({values}, event) => ({
...values,
apiDat: event.data, // save whatever values you need here
}),
}),
},
guards: {
// this requires a definition based on firebase's returned api call on a success
isSuccess: ({values}) => typeof values.apiDat.data !== 'undefined',
// this requires a definition based on firebase's returned api call when the call is unauthorized
isUnauthorized: ({values}) => typeof values.apiDat.detail !== 'undefined' && values.apiDat.detail === 'invalid_auth',
}
});