cultofcoders:meteor-flux

v0.0.4Published 8 years ago

This package has not had recent updates. Please investigate it's current state before committing to using it in your project.

Flux for Meteor

This is the most basic, most intuitive, and easy to use flux implementation.

You have a single main store in your dispatcher. You can use multiple stores in your store.

The Store

Store is an extended version of local Mongo.Collection.

let store = new Store(defaults); // optionally specify defaults
// if defaults is an array, it will do inserts in the store
// if defaults is an object, it will insert documents as {key, value}
// this means that if defaults = [{key: 'xxx'}, {value: 'yyy'}], it will be equivalent if with {'xxx': 'yyy'}

store.set('key', 'value'); // value can be object, function, array, whatever
store.get('key'); // returns the value, returns undefined if it can't find it
store.get('key', defaultValue);  // returns the value, returns defaultValue it can't find it.

// if you are using store for arrays
store.fetch(filters, options) will return all elements from it using filters and options as you are accustomed with .find().fetch()

// by default the fetch() in Store is reactive!
// this can help you avoid subscribing to a store in Blaze.

// if you want to disable reactivity, for any reason:
store.fetch({}, {reactive: false});

Store Events

store.subscribe(callback) // will call the callback whenever the store changes.
// unsubscribing from a store
let unsubscribe = store.subscribe(callback);
unsubscribe();
// or
store.unsubscribe(callback);

// listen to store events
store.on('updated', callback) // this is exactly similar to subscribe

// http://docs.meteor.com/api/collections.html#Mongo-Cursor-observe
// only exposes 'changed', 'added', 'removed' with the same params
// when any of this event happens, the 'updated' event is also triggered

store.on('changed', (newDocument, oldDocument) => {
    // if you play with set, oldDocument.key will equal newDocument.key
})
store.on('added', (document) => {});
store.on('removed', (document) => {});

store.forceUpdate() // will trigger the 'updated' event.

Dispatcher

The dispatcher has one store. It's own store.

let dispatcher = new Dispatcher(defaults); // optionally specify defaults, that will be passed to the store
dispatcher.store // access the main store of the dispatcher

// listening to a single action
dispatcher.register('ADD_TODO', ({data, store}) => {
    // do stuff with the store
    store.get('todos').insert({ ... });
})

// listening to all dispatched actions
dispatcher.register(({action, data, store}) => {
    if (action === 'ADD_TODO') { ... }
})

// dispatching actions
dispatcher.emit('ACTION_STRING', data);

// listening to events
dispatcher.store.subscribe(callback);

Updating Array/Object Elements in Stores

// listening to all dispatched actions

dispatcher.register(({action, data, store}) => {
    switch (action) {
        case 'ADD_TODO':
            store.get('todos').insert(data);
        case 'UPDATE_TODO':
            const {_id, ...toDoData} = data;
            store.get('todos').update(_id, {$set: toDoData});
        case 'SET_SPECIAL_FILTER':
            store.update('filters', {$set: {'specialFilter': data});
    }
})

Nesting Stores

If you store the application state in one place, that place can become huge, and every change happening in a small portion of your app, will propagate to many unecessary listeners. However, you can listen to changes on specific stores.

const dispatcher = new Dispatcher({
    'filters': new Store({
        date: null,
        whatever: null,
        moreComplexity: new Store({
            importantData: null
        })
    });
})

const filters = dispatcher.store.get('filters')
filters.get('moreComplexity').subscribe(callback)

Nested stores don't propagate "updated" event to the parent by default. However you can configure them to do so in the constructor:

const dispatcher = new Dispatcher({
    'filters': new Store({
        date: null,
        whatever: null,
        moreComplexity: new Store({
            importantData: null
        }, {propagate: true}) // this will propagate updated event to the filters store
    }, {propagate: true}); // this will propagate event to the main store.
})
// using the code above means that any change done in moreComplexity, will trigger update in the main store (dispatcher.store)

Registering actions that play with nested stores:

dispatcher.register('ACTION', ({store, data}) => {
    const localStore = store.get('filters').get('moreComplexity');
    localStore.set('something', 'somethingElse')
})

Use it with Blaze

import {Dispatcher, Store} from 'meteor/cultofcoders:meteor-flux';

let dispatcher = new Dispacher({
    todos: new Store(),
    filters: 'all'
});

dispatcher.register('ADD_TODO', ({data, store}) => {
    let todos = store.get('todos')
    todos.insert(data);
});

Template.ToDoList.helpers({
    todos() {
        let todos = dispatcher.store.get('todos');
        
        return todos.fetch();
    }
});

Template.ToDoList.events({
    'click .js-add-todo'(e) {
        dispatcher.emit('ADD_TODO', {text: 'Understand Flux'});
    }
});

More documentation on how to use with React will follow.

To do...