Skip to content

Instantly share code, notes, and snippets.

@jruif
Forked from developit/*state-machine-component.md
Last active September 7, 2017 18:01
Show Gist options
  • Select an option

  • Save jruif/0210f21a1f8c10643faa9cd05b5c5e09 to your computer and use it in GitHub Desktop.

Select an option

Save jruif/0210f21a1f8c10643faa9cd05b5c5e09 to your computer and use it in GitHub Desktop.

Revisions

  1. jruif revised this gist Sep 7, 2017. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions machine.js
    Original file line number Diff line number Diff line change
    @@ -4,8 +4,8 @@ export default (reducer, render) => {
    function Machine() {
    Component.call(this);
    let cache = {};
    let action = (type,...other) => cache[type] || (cache[type] = data => {
    this.setState(reducer(this.state, { type, data, props: this.props, other }));
    let action = (type, other) => cache[type] || (cache[type] = data => {
    this.setState(reducer(this.state, { type, data, props: this.props, ...other }));
    });
    this.render = (props, state) => render(state, action);
    this.componentWillReceiveProps = action('@@PROPS');
  2. jruif revised this gist Sep 7, 2017. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions machine.js
    Original file line number Diff line number Diff line change
    @@ -4,8 +4,8 @@ export default (reducer, render) => {
    function Machine() {
    Component.call(this);
    let cache = {};
    let action = type => cache[type] || (cache[type] = data => {
    this.setState(reducer(this.state, { type, data, props: this.props }));
    let action = (type,...other) => cache[type] || (cache[type] = data => {
    this.setState(reducer(this.state, { type, data, props: this.props, other }));
    });
    this.render = (props, state) => render(state, action);
    this.componentWillReceiveProps = action('@@PROPS');
  3. @developit developit revised this gist Sep 6, 2017. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions *state-machine-component.md
    Original file line number Diff line number Diff line change
    @@ -2,6 +2,8 @@

    A tiny (265 byte) utility to create state machine components using two pure functions.

    🔥 [**JSFiddle Demo**](https://jsfiddle.net/developit/x0td4bmy/)

    ### Usage

    The API is a single function that accepts 2 pure functions as arguments:
  4. @developit developit revised this gist Sep 6, 2017. 1 changed file with 11 additions and 2 deletions.
    13 changes: 11 additions & 2 deletions *state-machine-component.md
    Original file line number Diff line number Diff line change
    @@ -4,18 +4,27 @@ A tiny (265 byte) utility to create state machine components using two pure func

    ### Usage

    The API is a single function that accepts 2 pure functions as arguments:

    ```js
    // The factory accepts 2 functions
    stateMachineComponent(reduce, render)
    ```

    The first function, `reduce()`, takes in the current state and applies an `action` to it, similar to a reducer in Redux:

    ```js
    // Reduce is a redux-style reducer
    function reduce(state, action) {
    // actions are like Redux Standard Actions:
    let { type, data, props } = action

    return { } // new state
    return { } // just return the new state
    }
    ```

    The second function, `render()`, is a pure functional component that gets passed the current `state` instead of `props`, and a second argument `action()` - a function that creates a bound dispatcher for the given action type:

    ```js
    // Render is a functional component with little twist
    function render(state, action) {
    // action() creates a dispatcher for an action type:
  5. @developit developit revised this gist Sep 6, 2017. No changes.
  6. @developit developit revised this gist Sep 6, 2017. No changes.
  7. @developit developit revised this gist Sep 6, 2017. No changes.
  8. @developit developit revised this gist Sep 6, 2017. No changes.
  9. @developit developit revised this gist Sep 6, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion *state-machine-component.md
    Original file line number Diff line number Diff line change
    @@ -64,7 +64,7 @@ const ToDos = stateMachineComponent(
    // state, action(type)
    ({ todos, text }, action) => (
    <div>
    <h2>State Machine ToDo's</h2>
    <h2>State Machine ToDos</h2>
    <ul>{todos.map( todo => <li>{todo}</li> )}</ul>
    <form onSubmit={action('ADD')}>
    <input value={text} onInput={action('TEXT')} />
  10. @developit developit revised this gist Sep 6, 2017. 2 changed files with 1 addition and 1 deletion.
    File renamed without changes.
    2 changes: 1 addition & 1 deletion package.json
    Original file line number Diff line number Diff line change
    @@ -12,7 +12,7 @@
    "transpile": "rollup -c --environment FORMAT:umd && rollup -c --environment FORMAT:cjs && rollup -c --environment FORMAT:es",
    "size": "strip-json-comments --no-whitespace dist/machine.js | gzip-size",
    "test": "eslint machine.js",
    "prepublish": "npm run build && cp *README.md README.md"
    "prepublish": "npm run build && cp \"*state-machine-component.md\" README.md"
    },
    "eslintConfig": {
    "extends": "eslint:recommended",
  11. @developit developit revised this gist Sep 6, 2017. 2 changed files with 4 additions and 2 deletions.
    1 change: 1 addition & 0 deletions .gitignore
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,4 @@
    node_modules
    npm-debug.log
    dist
    README.md
    5 changes: 3 additions & 2 deletions package.json
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,7 @@
    {
    "name": "state-machine-component",
    "amdName": "stateMachineComponent",
    "version": "1.0.1",
    "version": "1.0.2",
    "description": "Create tiny pure state machine components.",
    "source": "machine.js",
    "module": "dist/machine.es.js",
    @@ -11,7 +11,8 @@
    "build": "npm run transpile && npm run size",
    "transpile": "rollup -c --environment FORMAT:umd && rollup -c --environment FORMAT:cjs && rollup -c --environment FORMAT:es",
    "size": "strip-json-comments --no-whitespace dist/machine.js | gzip-size",
    "test": "eslint machine.js"
    "test": "eslint machine.js",
    "prepublish": "npm run build && cp *README.md README.md"
    },
    "eslintConfig": {
    "extends": "eslint:recommended",
  12. @developit developit revised this gist Sep 6, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion package.json
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,7 @@
    {
    "name": "state-machine-component",
    "amdName": "stateMachineComponent",
    "version": "1.0.0",
    "version": "1.0.1",
    "description": "Create tiny pure state machine components.",
    "source": "machine.js",
    "module": "dist/machine.es.js",
  13. @developit developit created this gist Sep 6, 2017.
    75 changes: 75 additions & 0 deletions *README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,75 @@
    # state-machine-component

    A tiny (265 byte) utility to create state machine components using two pure functions.

    ### Usage

    ```js
    // The factory accepts 2 functions
    stateMachineComponent(reduce, render)

    // Reduce is a redux-style reducer
    function reduce(state, action) {
    // actions are like Redux Standard Actions:
    let { type, data, props } = action

    return { } // new state
    }

    // Render is a functional component with little twist
    function render(state, action) {
    // action() creates a dispatcher for an action type:
    return <button onClick={ action('TYPE') } />
    }
    ```

    ### Simple Example: Counter

    ```js
    // Remember:
    // `state` is the current state.
    // `action` is a redux standard action.
    function reduce(state, action) {
    switch (action.type) {
    case '@@INIT': return { count: 0 }
    case 'ADD': return { count: state.count+1 }
    }
    }

    function render(state, action) {
    return (
    <div class="counter">
    Current count: {state.count}
    <button onClick={action('ADD')}>Add 1</button>
    </div>
    )
    }

    stateMachineComponent(reduce, render)
    ```


    ### Full Example: To-Do List

    ```js
    const ToDos = stateMachineComponent(
    // (state, action)
    ({ todos, text }, { type, data, props }) => {
    switch (type) {
    case '@@INIT':return { todos: props.todos || [], text: '' };
    case 'ADD': return { todos: todos.concat(text), text: '' };
    case 'TEXT': return { text: data.target.value };
    }
    },
    // state, action(type)
    ({ todos, text }, action) => (
    <div>
    <h2>State Machine ToDo's</h2>
    <ul>{todos.map( todo => <li>{todo}</li> )}</ul>
    <form onSubmit={action('ADD')}>
    <input value={text} onInput={action('TEXT')} />
    </form>
    </div>
    )
    );
    ```
    3 changes: 3 additions & 0 deletions .gitignore
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,3 @@
    node_modules
    npm-debug.log
    dist
    15 changes: 15 additions & 0 deletions machine.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,15 @@
    import { Component } from 'preact';

    export default (reducer, render) => {
    function Machine() {
    Component.call(this);
    let cache = {};
    let action = type => cache[type] || (cache[type] = data => {
    this.setState(reducer(this.state, { type, data, props: this.props }));
    });
    this.render = (props, state) => render(state, action);
    this.componentWillReceiveProps = action('@@PROPS');
    this.componentWillMount = action('@@INIT');
    }
    return (Machine.prototype = new Component()).constructor = Machine;
    };
    47 changes: 47 additions & 0 deletions package.json
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,47 @@
    {
    "name": "state-machine-component",
    "amdName": "stateMachineComponent",
    "version": "1.0.0",
    "description": "Create tiny pure state machine components.",
    "source": "machine.js",
    "module": "dist/machine.es.js",
    "main": "dist/machine.js",
    "umd:main": "dist/machine.umd.js",
    "scripts": {
    "build": "npm run transpile && npm run size",
    "transpile": "rollup -c --environment FORMAT:umd && rollup -c --environment FORMAT:cjs && rollup -c --environment FORMAT:es",
    "size": "strip-json-comments --no-whitespace dist/machine.js | gzip-size",
    "test": "eslint machine.js"
    },
    "eslintConfig": {
    "extends": "eslint:recommended",
    "env": {
    "node": true
    },
    "parserOptions": {
    "sourceType": "module"
    }
    },
    "files": [
    "machine.js",
    "dist"
    ],
    "keywords": [
    "preact",
    "component",
    "state machine",
    "redux"
    ],
    "author": "Jason Miller <[email protected]>",
    "license": "MIT",
    "devDependencies": {
    "eslint": "^4.6.1",
    "gzip-size": "^3.0.0",
    "rollup": "^0.49.2",
    "rollup-plugin-buble": "^0.15.0",
    "rollup-plugin-post-replace": "^1.0.0",
    "rollup-plugin-uglify": "^2.0.1",
    "strip-json-comments-cli": "^1.0.1",
    "uglify-js": "^2.8.29"
    }
    }
    41 changes: 41 additions & 0 deletions rollup.config.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,41 @@
    import fs from 'fs';
    import buble from 'rollup-plugin-buble';
    import uglify from 'rollup-plugin-uglify';
    import replace from 'rollup-plugin-post-replace';

    let pkg = JSON.parse(fs.readFileSync('./package.json'));

    let format = process.env.FORMAT;

    export default {
    strict: false,
    sourcemap: true,
    exports: 'default',
    input: pkg.source,
    output: {
    format,
    name: pkg.amdName,
    file: format==='es' ? pkg.module : format==='umd' ? pkg['umd:main'] : pkg.main
    },
    external: ['preact'],
    globals: {
    preact: 'preact'
    },
    plugins: [
    buble(),
    format==='cjs' && replace({
    'module.exports = index;': '',
    'var index =': 'module.exports ='
    }),
    format==='umd' && replace({
    'return index;': '',
    'var index =': 'return'
    }),
    format!=='es' && uglify({
    output: { comments: false },
    mangle: {
    toplevel: format==='cjs'
    }
    })
    ]
    };