Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
another redux-ish C in MVC
var Controller=function(){return function(t){var n=this;this.p=[],this.l=[],this.getState=function(){return n.s},this.addPlugin=function(t){n.p.push(t)},this.removePlugin=function(t){n.p=n.p.filter(function(n){return n!==t})},this.addListener=function(t){n.l.push(t)},this.removeListener=function(t){n.l=n.l.filter(function(n){return n!==t})},this.dispatch=function(t){n.p.forEach(function(n){return t=n(t)});var i=t(n.s);n.s!==i&&(n.s=i,n.l.forEach(function(t){return t(n.s,n.dispatch)}))},this.s=t}}();
export interface IReducer<S = any> {
(state: Readonly<S>): Readonly<S>;
}
export interface IDispatch<S = any> {
(reducer: IReducer<S>): void;
}
export interface IListener<S = any> {
(state: S, dispatch: IDispatch<S>): void;
}
export interface IPlugin<S = any> {
(reducer: IReducer<S>): IReducer<S>;
}
export class Controller<S = any> {
private state: S;
private plugins: IPlugin<S>[] = [];
private listeners: IListener<S>[] = [];
constructor(initialState: S) {
this.state = initialState;
}
public getState = () => this.state;
public addPlugin = (plugin: IPlugin<S>) =>{
this.plugins.push(plugin);
}
public removePlugin = (plugin: IPlugin<S>) => {
this.plugins = this.plugins.filter(p => p !== plugin);
}
public addListener = (listener: IListener<S>) => {
this.listeners.push(listener);
}
public removeListener = (listener: IListener<S>) => {
this.listeners = this.listeners.filter(l => l !== listener);
}
public dispatch = (reducer: IReducer<S>) => {
this.plugins.forEach(p => (reducer = p(reducer)));
const result = reducer(this.state);
// important: state should be immutable
if (this.state !== result) {
this.state = result;
this.listeners.forEach(l => l(this.state, this.dispatch));
}
};
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script type="module">
import {
h,
patch
} from "//unpkg.com/superfine@6.0.1/src/index.js?module";
// https://gist.github.com/tscholl2/4de700ff933d8226fb8b56964547fffe
eval(
"function Controller(t){var n=this;this.plugins=[],this.listeners=[],this.getState=function(){return n.state},this.dispatch=function(t){n.plugins.forEach(function(n){return t=n(t)});var e=t(n.state);n.state!==e&&(n.state=e,n.listeners.forEach(function(t){return t(n.state,n.dispatch)}))},this.state=t}Controller.prototype.addPlugin=function(t){this.plugins.push(t)},Controller.prototype.removePlugin=function(t){this.plugins=this.plugins.filter(function(n){return n!==t})},Controller.prototype.addListener=function(t){this.listeners.push(t)},Controller.prototype.removeListener=function(t){this.listeners=this.listeners.filter(function(n){return n!==t})};window.Controller = Controller;"
);
function App(dispatch) {
const increment = () => dispatch(state => state + 1);
const decrement = () => dispatch(state => state - 1);
return state => {
return h("div", null, [
h("h1", null, `State = ${state}`),
h("button", { onclick: increment }, "+"),
h("button", { onclick: decrement }, "-")
]);
};
}
function start(state = 0) {
const controller = new Controller(state);
const view = App(controller.dispatch);
let node = undefined;
const update = () => {
node = patch(node, view(controller.getState()), document.body);
};
controller.addListener(update);
update();
}
document.addEventListener("DOMContentLoaded", () => start());
</script>
</head>
<body></body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment