XState react-在多个组件之间共享机器实例

时间:2019-12-03 12:57:15

标签: reactjs react-native xstate

我有两台机器:AuthenticationMachineAddressMachineLogin component使用AuthenticationMachine,Address component使用AddressMachine。但是我需要来自AddressMachine的token地址组件中的地址才能与AddressMachine一起使用。我曾尝试在AuthenticationMachine中生成Actor,但没有用。

身份验证机器

const createService = (context: {token: string}) => {
  return Machine({
    id: 'service',
    initial: 'logged_in',
    states: {
      logged_in: {},
      logged_out: {},
    },
  }).withContext(context);
};

const authenticationMachine = Machine(
  {
    id: 'authenticationMachine',
    initial: 'unauthenticated',
    context: {
      token: undefined,
      error: undefined,
      service: undefined,
    },
    states: {
      unauthenticated: {
        on: {
          LOGIN: 'authenticating',
        },
      },
      authenticating: {
        invoke: {
          src: 'login',
          onDone: {
            target: 'loggedIn',
            actions: assign({
              token: (ctx, event: any) => event.data.access_token,
              service: (ctx, event) => {
                return spawn(createService({token: event.data.access_token}));
              },
            }),
          },
          onError: {
            target: 'unauthenticated',
            actions: assign({
              error: (ctx, event: any) => event.data,
            }),
          },
        },
      },
      loggedIn: {
        on: {
          LOGOUT: 'unauthenticated'
        },
      },
    },
  },
);

1 个答案:

答案 0 :(得分:0)

我认为这可能是您使用Assign或只是实现问题组件的方式。

这是codesandbox

中组件中的机器的有效示例

还有一个简单的示例,说明如何在组件中使用机器:

地址组件:

function Address(props) {
  const [current] = useService(props.service);
  return <>Address Component token: {current.context.token}</>;
}

登录组件:

export default function Login() {
  const [current, send] = useMachine(authenticationMachine);
  const isUnauthenticated = current.matches("unauthenticated");
  const isAuthenticating = current.matches("authenticating");
  const isLoggedIn = current.matches("loggedIn");

  if (isUnauthenticated) {
    return (
      <>
        token: {current.context.token}
        <br />
        <button onClick={() => send("LOGIN")}>Login</button>
      </>
    );
  }
  if (isAuthenticating) {
    return <>...hold on, authenticating</>;
  }
  if (isLoggedIn) {
    return (
      <>
        token: {current.context.token}
        <br />
        <button onClick={() => send("LOGOUT")}>Logout</button>
        <br />
        <Address service={current.context.service} />
      </>
    );
  }
}

您的机器示例已展开:

import { assign, Machine, spawn } from "xstate";

const createService = (context: { token: string }) => {
    return Machine({
        id: 'service',
        initial: 'logged_in',
        states: {
            logged_in: {},
            logged_out: {},
        },
    }).withContext(context);
};

const login = (ctx) => {
    const { email, pw } = ctx;
    return new Promise((resolve, reject) => {
        if(email === 'a@b.c' && pw === 'abc') {
            return resolve({ token: 'jahsfjkhakjsnfj'});
        } else {
            return reject({ token: undefined });
        }
    });
};

const authenticationMachine = Machine(
    {
        id: 'authenticationMachine',
        initial: 'unauthenticated',
        context: {
            token: undefined,
            error: undefined,
            service: undefined,
            email: 'a@b.c',
            pw: 'abc'
        },
        states: {
            unauthenticated: {
                on: {
                    LOGIN: 'authenticating',
                },
            },
            authenticating: {
                invoke: {
                    id: 'login',
                    src: context => login(context),
                    onDone: {
                        target: 'loggedIn',
                        actions: [
                            assign({ token: (_, event) => event.data.token }),
                            assign({ service: (_, event) => {
                                return spawn(createService({token: event.data.token}));
                            }})
                        ]
                    },
                    onError: { target: 'unauthenticated' },
                },
            },
            loggedIn: {
                on: {
                    LOGOUT: 'unauthenticated'
                },
            },
        },
    }
);

export { authenticationMachine };