有没有办法使用从 Firebase 返回的承诺来初始化 Xstate 状态机?

问题描述

我正在尝试使用 Firebase 保持状态。我目前正在使用“saveState”函数,该函数运行良好,并将最新状态正确保存到 Firebase。

现在我希望能够根据 Firebase 中最近保存的状态初始化状态机。在下面的代码中,我试图使用我的“loadState”函数为 Xstate 提供一个配置对象。它目前返回一个带有正确状态配置的承诺。

这是我的“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:无法读取未定义的属性‘数据’”,我认为这是因为承诺尚未解决导致尝试读取未定义的值。

这到底是可能的还是我做错了?

我对这一切都很陌生,任何指导将不胜感激。谢谢。

解决方法

我想您可以使用 useEffect 来更新您的状态机。

在状态机中调用 fetch 怎么样?


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',}

});