Skip to content

Instantly share code, notes, and snippets.

@RafalFilipek
Created November 24, 2019 22:18
Show Gist options
  • Save RafalFilipek/1d9b38b350abe6db5f23433a1f5b9204 to your computer and use it in GitHub Desktop.
Save RafalFilipek/1d9b38b350abe6db5f23433a1f5b9204 to your computer and use it in GitHub Desktop.
1 hour with xstate
/**
* xstate - 4.7.0-rc.6
* typescript - 3.7.2
*/
import React from "react";
import { createMachine, assign } from "xstate";
import { useMachine } from "@xstate/react";
interface Context {
name?: string;
}
type Event = { type: "SET_NAME"; name: string } | { type: "RESET" };
type State =
| { value: "unknown"; context: Context }
| { value: "named"; context: Context & { name: string } };
const m = createMachine<Context, Event, State>(
{
initial: "named",
states: {
unknown: {
on: { SET_NAME: { target: "named", actions: ["cacheName"] } }
},
named: {
on: {
RESET: { target: "unknown", actions: ["resetName"] }
}
}
}
},
{
actions: {
// No easy way to make types correct (`event` should be `SET_NAME`)
cacheName: assign({ name: (_ctx, event) => event.name })
// can't omit arguments like
resetName: assign({ name: () => undefined })
}
}
);
const App = () => {
const [current, send] = useMachine(m);
if (current.matches("named")) {
{
/* `context.name` should be `string` instead of `string | undefined` */
}
return <span>{current.context.name.toUpperCase()}</span>;
}
return (
<div>
<button onClick={() => send({ type: "SET_NAME", name: "Rafał" })}>
set
</button>
</div>
);
};
@RafalFilipek
Copy link
Author

This is my simplest / final version. I've tried using Machine(...), useMachine from @xstate/fsm and some other combinations. I know I can use as in some places or simple if and checks in render phrase. Hope there are some less manual solutions :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment