Skip to content

davidxi/flux-factory

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

npm

flux-factory

A Flux pattern wrapper to let you write less Flux structure code.

Why less code

Let's revisit the Flux structure

Flux Architecture

Now, imagine you have a form page where all form inputs are implemented in react. So each form field has:

  1. a variable in the store module to cache its value;
  2. a seperate if logic in the dispatcher callback to invoke some setter method to update its value
  3. a dispatcher instance
  4. a setter method in action module to call the dispatcher
  5. some constant variables defined in constant module to be used in both actions and store

This is not a big deal for a simple Todo app. However, as we add more and more data fields in the store, we have to add all 5 places as stated above (and mostly they are kinda duplicated code compared to existing code).

Also, this patter introduces some code coupling. For example, if we want modify a constant declare in the constant module, i have to modify other palces in both actions and store.

So, is it possible that when we add or redeine a data field, we can utilize some sort of factory function, such that we only need to modify one place (ie, constant module), and all the other places would be automatically added and updated (ie, action, dispatcher, store modules)?

With flux-factory, the answer is yes. Now, let's look at the following example.

Dependencies

  • es5-shim (if needed)
  • flux
  • immutable (optional)

Usage

var fluxFactory = require('flux-factory');

var allDataFields = {
  // 'data-field-key': 'action setter params list'
  profileName: ['name'],
  birthday: ['year', 'month', 'day'],
  gender: ['gender'],
  hometown: ['cityId', 'countryId'],
  relationship: ['status', 'relatedUserId']
};

var fluxEntityName = 'UserProfile';

// initialize with dependencies libraries

fluxFactory.init({
    init: require('flux'),
    immutable: null   // OR require('immutable')
});

// generate action/dispatcher/store

fluxFactory.make(fluxEntityName, allDataFields);

// now let's try call an action, and listen to the change event from store.

var Action = fluxFactory.useAction(fluxEntityName);
var Store = fluxFactory.useStore(fluxEntityName);

Store.addChangeListener(function(dataFieldKey) {
    // usually, you can put this function in your react component
    console.log('data changed on field: ' + dataField);
    console.log(Store.getBirthday());
});

// the action setter arguments list format is as defined in 'allDataFields'
Action.updateBirthday('yyyy', 'mm', 'dddd');

Now, what did flux-factory do in the underhood?

(1) First, it automatically creates a constant object as formatted below:

/* constant object auto generated */
constant = {
  DataFields: {
    PROFILE_NAME: ..
    BIRTHDAY: ..
    GENDER: ..
    ...
  },
  ActionTypes: {
    UPDATE_PROFILE_NAME: ..
    UPDATE_BIRTHDAY: ..
    UPDATE_GENDER: ..
    ...
  }
}

(2) Then, it automatically creates a dispatcher object, whose methods looks exactly like flux examples sample code.

By concept, since the dispatcher is used as a bridge between action module and store module, in most cases, you don't need to modify/extend this generated object.

(3) Then, it automatically creates a store object, which inherits from EventEmitter obejct (same as in flux sample code). Event subscribe/unsubscribe functions are also bound. It also implements getters and setters, and has the following properties created:

/* store object auto generated */
store = assign(new EventEmitter, {

	// invoked when data changes, if you didn't overwrite default setters.
	// if you included 'immutable', it is only invoked when results has diff.
	emitchange: {field_key},
	addChangeListener: {handler},

	// getters
	getProfileName => {name},
	getBirthday => {year, month, day},
	getGender => {gender},
	....

	// setters
	updateProfileName: {name},
	updateBirthday: {year, month, day},
	updateGender: {gender},
	....

	dispatchToken = payload => {
	  if (payload.action.type ===
	  	  constant.actionType.UPDATE_PROFILE_NAME) {
	  	  store.updateProfileName(payload.data)
	  }
	  if (payload.action.type ===
	  	  constant.actionType.UPDATE_BIRTHDAY) {
	  	  store.updateBirthday(payload.data)
	  }
	  ...
	  this.onDispatcherPayload(payload);
	},
	onDispatcherPayload => (empty func) // overwrite if you need
})

So you can extend this generated store object by yourself, to implement those data field values setter functions. (They were created to be empty function initially).

(4) Lastly, it automatically creates an action object, which has all the setter function which leads to invoke correspoding store setter function through the dispatcher module.

/* action object auto generated */
action = {
  updateProfileName: function(name),
  updateBirthday: function(year, month, day),
  updateGender: function(gender),
  ....
}

flux-factory already sets up correct ActionType and arguments list in each setter function, therefore each setter function should go to correct store setter function; and the data property name should be the same as you defined in the config object when you call make(config, namespace) in the beginning. So, in most cases, you don't need modify this generated action object.

###SO, All in all, once you defined the config mapping between data field name and its setter function arguments list variable names; all you need to do, is to implement store setter functions for each data field. (note that there is no need to modify generated action setter functions). And all the logic between actions and store is already implemented.

And how to extend those generated action/constant/dispatcher/store object?

fluxFactory.make('UserProfile', {config mapping})

var action = fluxFactory.useAction('UserProfile');
var constant = fluxFactory.useConstant('UserProfile');
var dispatcher = fluxFactory.useDispatcher('UserProfile');
var store = fluxFactory.useStore('UserProfile');

And of course, you can also pass in a batched config mapping to created action/constant/dispatcher/store for multiple entities:

fluxFactory.make({
  UserProfile: {mapping ...},
  Notifications: {mapping ...}
});

var userStore = fluxFactory.useStore('UserProfile');
var notificationStore = fluxFactory.useStore('Notifications');

About

Make you write 50% less Flux structure code

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published