Skip to content

Instantly share code, notes, and snippets.

@lamtranweb
Created May 25, 2019 06:52
Show Gist options
  • Save lamtranweb/6b2f373bc35f4e148861ab0ccb3f41da to your computer and use it in GitHub Desktop.
Save lamtranweb/6b2f373bc35f4e148861ab0ccb3f41da to your computer and use it in GitHub Desktop.
ts-remote-data-xstate
import * as React from "react";
import { render } from "react-dom";
import RemoteData from "ts-remote-data";
import { Machine, assign, DefaultContext } from "xstate";
import { useMachine } from "@xstate/react";
import { useEffect, useMemo, ReactNode } from "react";
import "./styles.css";
const URL = "https://jsonplaceholder.typicode.com/todos/1";
interface Todo {
id: number;
userId: number;
title: string;
completed: boolean;
}
type MyTodo = RemoteData<Todo>;
interface Context {
data: MyTodo;
}
const fetchMachine = Machine<Context>({
id: "fetch",
initial: "not_asked",
context: {
data: RemoteData.NOT_ASKED
},
states: {
not_asked: {
on: { FETCH: "loading" }
},
loading: {
invoke: {
src: (_context, _event) => {
return fetch(URL).then(res => res.json());
},
onDone: {
target: "success",
actions: assign({
data: (_: Context, e: { data: MyTodo }) => {
return e.data;
}
})
},
onError: {
target: "failure",
actions: assign({
data: (_: Context, e: { data: TypeError }) => {
return RemoteData.failWith(e.data);
}
})
}
}
},
success: {
type: "final"
},
failure: {
type: "final"
}
}
});
function App() {
const customFetchMachine = useMemo(
() => fetchMachine,
[] // Machine should never change
);
const [current, send] = useMachine(customFetchMachine);
useEffect(() => {
send("FETCH");
}, [send]);
let State: ReactNode = null;
switch (current.value) {
case "not_asked":
State = null;
break;
case "loading":
State = <h1>Loading</h1>;
break;
case "success":
const myTodo = RemoteData.asReady(current.context.data);
State = <h1>{myTodo.title}</h1>;
break;
case "failure":
const error = RemoteData.asFailure(current.context.data)
.error as TypeError;
State = <h1>{error.message}</h1>;
break;
default:
State = <h1>HUH?</h1>;
}
return <div className="App">{State}</div>;
}
const rootElement = document.getElementById("root");
render(<App />, rootElement);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment