Skip to content

Instantly share code, notes, and snippets.

@MattMcFarland
Last active December 5, 2019 11:29
Show Gist options
  • Save MattMcFarland/25fb4f0241530d2f421a to your computer and use it in GitHub Desktop.
Save MattMcFarland/25fb4f0241530d2f421a to your computer and use it in GitHub Desktop.
FLUX for Mithril

Table of Contents:

Why FLUX?

I prefer the FLUX pattern to MVC, and I have been successful in applying the FLUX pattern without running into too much trouble.

About this Guide

This mini-howto guide is intended for an audience with experience using FLUX. My personal experience with flux may easily be lesser than some of those reading. Please assume that I am happy to be corrected, should this guide imply anything that may be detrimental (other than using flux on its own of course ;))

Should there be a large enough audience, I will write a more comprehensive guide.

Library Dependencies

  • Mithril.js - Of course!
  • Bullet - an ultra-lightweight event emitter (0.975 kB minified, smaller when gzipped)
  • MSX support (I currently just use Browserify/Mithrilify, but I think babelify could be used later)

The React or Flux API libraries are NOT used.

Directory Structure

My filebase currently is comprised like so, (this is not optimized for scalability, as this is an experiment)

src/
	
	actions.js
	constants.js
	dispatcher.js
	index.js (browserify entry point)
	store.js

src/components

	...
	app.js

store.js

var Bullet = require('bullet-pubsub'),
    Constants = require('./constants'),
    _data = { showSidebar: false};


var Store = {

    getAll: function () {
        return {data: _data};
    },
    // Allow Controller-View to register itself with store
    addChangeListener: function (callback) {
        Bullet.on(Constants.CHANGE_EVENT, callback);
    },
    removeChangeListener: function (callback) {
        Bullet.removeListener(Constants.CHANGE_EVENT, callback);
    },
    // triggers change listener above, firing controller-view callback
    emitChange: function () {
        Bullet.trigger(Constants.CHANGE_EVENT);
    },

    dispatchIndex: function (payload) {
        console.log('PAYLOAD:', payload);
        switch (payload.type) {
            case Constants.ActionTypes.TEST_STORE:
                _data.message='test store works';
                Store.emitChange();
                break;
            case Constants.ActionTypes.SHOW_SIDEBAR:
                _data.showSidebar = true;
                Store.emitChange();
                break;
            case Constants.ActionTypes.HIDE_SIDEBAR:
                _data.showSidebar = false;
                Store.emitChange();
                break;

        }
    }

};

module.exports = Store;

constants.js

module.exports = {
    CHANGE_EVENT: 'CHANGE_EVENT',

    ActionTypes: {
        TEST_STORE: 'TEST_STORE',
        SHOW_SIDEBAR: 'SHOW_SIDEBAR',
        HIDE_SIDEBAR: 'HIDE_SIDEBAR'
    }
};

dispatcher.js

var Store = require('./store');

module.exports = function (payload) {

    Store.dispatchIndex(payload);

};

actions.js

var Constants = require('./constants');
var Dispatcher = require('./dispatcher');

module.exports = {

    testStore: function (data) {
        Dispatcher({
            type: Constants.ActionTypes.TEST_STORE,
            data: data
        })
    },
    showSidebar: function () {
        Dispatcher({
            type: Constants.ActionTypes.SHOW_SIDEBAR
        });
    },
    hideSidebar: function () {
        Dispatcher({
            type: Constants.ActionTypes.HIDE_SIDEBAR
        });
    }


};

app.js

require('./app.less');

// Framework
var Store = require('../store'),
    Actions = require('../actions');

// Sub-Components
var TopNav = require('./topnav'),
    Sidebar = require('./sidebar'),
    PostList = require('./PostList');

var App = {
    state: {
        data: {}
    },
    _onChange: function () {
        App.state = Store.getAll();
    },
    controller: function() {
        return {
            onunload: function () {
                Store.removeChangeListener(App._onChange);
            }
        }
    },
    view: function(ctrl) {
        return (
            <div>
                <TopNav/>
                <Sidebar/>
                <div class="container-fluid">
                    <PostList/>
                </div>
            </div>
        )
    }
};

Store.addChangeListener(App._onChange);


module.exports = App;
@alvieirajr
Copy link

Are you have the topnav, sidebar, PostList and app.less element ?

@cadesalaberry
Copy link

From your view function, it seems like you are returning a jsx component, not a mithril component. Is that correct ?

view: function(ctrl) {
  return (
    <div>
      <TopNav/>
      <Sidebar/>
      <div class="container-fluid">
        <PostList/>
      </div>
    </div>
  )
}

@niahoo
Copy link

niahoo commented Jan 11, 2016

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