Continuing from where we left off in part 1, I want to do three things here:
Set up project for Flux work
Have a simple build process
Babby's first create entity
Project setup
Standard directory structure goes something like this:
src/
app.js -- the entry point of your application and build target
actions/ -- the actions used by your views
ExampleActions.js
components/ -- you can name this "views", your React components
ExampleApp.js
ExampleElement.js
ExampleRow.js
ExampleTable.js
constants/ -- your constants used to communicate between your actions and stores
ExampleConsants.js
dispatchers/ -- your dispatcher(s) for handling actions
ExampleDispatcher.js
stores/ -- your store
ExampleStore.js
In reality, you can choose to not use constants, but I like not having to depend on the action not having to coordinate the exact matching string ID with the store (also helps code analysis tools and whatnot).
Nothing too special in the code here. See the example repo for code details.
Build process
I like using Gulp to run tasks and Webpack to actually build my application. I use Pete Hunt's jsx-loader to handle loading my JS files and transforming JSX as needed.
I also like to use aliases to make requiring modules easier, and avoid using relative paths for things I need in multiple places. Relevant excerpt:
resolve: {
alias: {
ExampleStore$: path.join(__dirname, 'src/stores/ExampleStore.js'),
ExampleDispatcher$: path.join(__dirname, 'src/dispatchers/ExampleDispatcher.js'),
ExampleConstants$: path.join(__dirname, 'src/constants/ExampleConstants.js'),
ExampleActions$: path.join(__dirname, 'src/actions/ExampleActions.js'),
propsEqual$: path.join(__dirname, 'src/utils/propsEqual.js')
}
}
See example repo for my setup.
Create an entity through Flux
Here's all of the code required to do this:
constants/ExampleConstants.js:
var keyMirror = require('react/lib/keyMirror');
module.exports = keyMirror({
CREATE_ROW: null
// add more constants for more actions
});
actions/ExampleActions.js:
var ExampleDispatcher = require('ExampleDispatcher');
var ExampleConstants = require('ExampleConstants');
module.exports = {
createRow: function (content) {
ExampleDispatcher.handleViewAction({
actionType: ExampleConstants.CREATE_ROW,
content: content
});
}
// add more methods likewise
};
dispatchers/ExampleDispatcher.js:
var copyProperties = require('react/lib/copyProperties');
var Dispatcher = require('flux').Dispatcher;
module.exports = copyProperties(new Dispatcher, {
handleViewAction: function (action) {
this.dispatch({
source: 'VIEW_ACTION',
action: action
});
}
// add more methods for other action sources like the server
});
stores/ExampleStore.js:
var ExampleDispatcher = require('ExampleDispatcher');
var EventEmitter = require('events').EventEmitter;
var ExampleConstants = require('ExampleConstants');
var merge = require('react/lib/merge');
var CHANGE_EVENT = 'change';
var _appState = {
data: []
};
function generateRandom() {
return (Math.random() * Date.now() | 0).toString(36);
}
function createRow(content) {
_appState.data.push({
id: generateRandom(),
content: content,
metadata: [
generateRandom(),
generateRandom(),
generateRandom(),
generateRandom(),
generateRandom(),
generateRandom(),
generateRandom(),
generateRandom(),
generateRandom()
]
});
}
var ExampleStore = merge(EventEmitter.prototype, {
emitChange: function () {
this.emit(CHANGE_EVENT);
},
addChangeListener: function (callback) {
this.on(CHANGE_EVENT, callback);
},
removeChangeListener: function (callback) {
this.removeListener(CHANGE_EVENT, callback);
},
getAppState: function () {
return _appState;
},
dispatcherIndex: ExampleDispatcher.register(function (payload) {
var action = payload.action;
switch (action.actionType) {
case ExampleConstants.CREATE_ROW: {
createRow(action.content);
ExampleStore.emitChange();
break;
}
// likewise, create more cases to handle other constants & actions
}
return true; // return promise
})
});
module.exports = ExampleStore;
So as you can see, there's not too much code involved to do this. Just some basic pieces that you need to put together.
And so, call the action method whenever you need to create rows.
// more stuff
_createRow: function () {
ExampleActions.createRow((Math.random() * 1e10 | 0).toString(36));
},
render: function () {
if (!this.state) {
return null;
}
return (
<div className='example-app'>
<h1>This is an example app</h1>
<button
className="example-button"
onClick={this._createRow}>
<span className="example-button-span">
Create random row
</span>
</button>
<ExampleTable
data={this.state.data}
/>
</div>
);
// more stuff
What next?
Pure Render Mixin and "pure" components