Skip to content

Instantly share code, notes, and snippets.

@GarrettCannon
Last active February 2, 2021 17:40
Show Gist options
  • Save GarrettCannon/e6e01af5a372bb9fb133ab1004bd77d1 to your computer and use it in GitHub Desktop.
Save GarrettCannon/e6e01af5a372bb9fb133ab1004bd77d1 to your computer and use it in GitHub Desktop.
Svelte Elm like state management using built in Svelte stores
import { writable, Writable, get } from "svelte/store";
type Dispatch<A> = (action: A) => void;
type CmdEff<A> = () => Promise<A | undefined>;
type CmdNone = "CmdNone";
type Cmd<A> = CmdEff<A> | CmdNone;
export const cmdNone: CmdNone = "CmdNone";
export type Update<S, A> = (action: A, state: S) => [S, Cmd<A>];
type Store<S, A> = {
state: Writable<S>;
dispatch: Dispatch<A>;
};
export const initStore = <S, A>(
init: S,
reducer: Update<S, A>,
debug?: boolean
): Store<S, A> => {
const _state = writable(init);
const dispatch = (action: A) => {
_state.update((s) => {
const [state, cmd] = reducer(action, s);
if (cmd !== "CmdNone") {
cmd().then((x) => {
if (x) {
dispatch(x);
}
});
}
return state;
});
if (debug) {
console.log(action, get(_state));
}
};
return { state: _state, dispatch };
};
@GarrettCannon
Copy link
Author

GarrettCannon commented Nov 16, 2020

Basic usage example


type Inc = { type: "INC" };
type Dec = { type: "DEC" };
type Res = { type: "RES" };
type HTTP = { type: "HTTP" };
type HTTPErr = { type: "HTTPErr" };
type HTTPOk = { type: "HTTPOk" };

type State = {
	count: number;
};

type Action = Inc | Dec | Res | HTTP | HTTPErr | HTTPOk;

const update: Update<State, Action> = (action: Action, state: State) => {
	switch (action.type) {
		case "DEC":
			return [{ count: state.count - 1 }, cmdNone];
		case "INC":
			return [{ count: state.count + 1 }, cmdNone];
		case "RES":
			return [{ count: 0 }, cmdNone];
		case "HTTP":
			return [
				state,
				async () => {
					const req = await fetch("https://httpbin.org/get");
					if (req.ok) {
						return { type: "HTTPOk" };
					} else {
						return { type: "HTTPErr" };
					}
				},
			];
		case "HTTPOk":
			return [{ count: state.count + 1 }, cmdNone];
		case "HTTPErr":
			return [state, cmdNone];
		default: {
			return [state, cmdNone];
		}
	}
};

const initState: State = {
	count: 0,
};

export const { state, dispatch } = initStore(initState, update, true);```

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