Skip to content

Commit

Permalink
- Add React Connector addon
Browse files Browse the repository at this point in the history
- Quick ES6 rewrite
- More documentation, logo
  • Loading branch information
Alexandre Galays committed Aug 6, 2015
1 parent 11a7f50 commit ac6db3d
Show file tree
Hide file tree
Showing 17 changed files with 201 additions and 135 deletions.
97 changes: 76 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

# Fluxx
![fluxx-logo](http://i171.photobucket.com/albums/u320/boubiyeah/photon_small_zps6sgduwbx.png)

A straight to the point and efficient implementation of the [Facebook flux guidelines](http://facebook.github.io/flux/docs/overview.html).

Expand All @@ -9,17 +9,16 @@ The key elements are kept

but there is far less boilerplate.

Coming soon: React adapters

# Content
* [Stores](#stores)
* [Simple Store](#store)
* [Store](#store)
* [ActorStore](#actorStore)
* [Defining a store and its actions](#storeAndActions)
* [Depending on another store](#dependOn)
* [Preventing the changed event from being dispatched](#preventChangeEvent)
* [State machine](#stateMachine)
* [Manually redrawing the view on store change](#manualRedraw)
* [React Connector](#reactConnector)
* [Differences with the Facebook implementation](#facebookImplementation)
* [Full example](#fullExample)

Expand All @@ -28,28 +27,35 @@ Coming soon: React adapters
## Stores

There are two possible styles to create Stores in fluxx.
Choose the style you prefer, you can even mix the two styles in the same application.
As a rule of thumb, if you're using ES6, try to pick the simple `Store` as a default.

<a name="store"></a>
### Simple Store
**Store**
As a rule of thumb, if you're using ES6 and a view layer with a rich component model (e.g `React`), try to pick the simple `Store` as a default. It's more functional and only manages one state datum. Any data transformation must occur outside the store as the store itself has no API.

`Store` has a more functional style but is a bit more limited
**ActorStore**
On the other hand, `ActorStore` might be more suited when using near-stateless view layers (e.g `virtual-dom`)
where a richer OO Store can help compensate the statelessness of the view.


<a name="store"></a>
### Store

```javascript
var { Store, Action } = require('fluxx');
var otherStore = require('./otherStore');
import { Store, Action } from 'fluxx';
import otherStore from './otherStore';

var action = Action.create('increment', 'decrement');

var store = Store({
state: 0,
// The initial state
state: 0,

// Action handlers transforming the state
handlers: {
[action.increment]: (state, by) => state + by,
[action.decrement]: (state, by) => state - by
},

// Store dependencies
dependOn: otherStore
});

Expand All @@ -62,11 +68,11 @@ console.log(store.state == 25);

<a name="actorStore"></a>
### ActorStore
`ActorStore` has a more Object Oriented style


```javascript
var { ActorStore, Action } = require('fluxx');
var otherStore = require('./otherStore');
import { ActorStore, Action } from 'fluxx';
import otherStore from'./otherStore';

var action = Action.create('increment', 'decrement');

Expand Down Expand Up @@ -102,7 +108,7 @@ In any case, if you need to update a Store's state (usually a JSON-like tree) in
<a name="storeAndActions"></a>
### Defining a Store and its Actions
```javascript
var { ActorStore, Action } = require('fluxx');
import { ActorStore, Action } from 'fluxx';

var action = Action.create('init', 'increment', 'decrement');

Expand Down Expand Up @@ -166,7 +172,7 @@ ActorStore(function(on) {

var value = 0;

on(action.increment, function() {
on(action.increment, () => {
if (value < 100) value++;
else return NO_CHANGE;
});
Expand Down Expand Up @@ -212,7 +218,6 @@ push();

```


<a name="manualRedraw"></a>
## Manually redrawing the view on store change
```javascript
Expand All @@ -233,6 +238,41 @@ action.increment(33);

```

<a name="reactConnector"></a>
## React connector

When using `React` and `Store`, you can wrap a component in a Connector for it to be automatically redrawn when
an Array of stores changes.
Note: `ReactConnector` only understand `Store` instances; It's also quite opinionated and won't redraw its children if all the Store's states are still stricly equal to their previous values (to discourage in-place mutations).
At this time, it is not possible to dynamically change the Store array.

```javascript
import Fluxx from 'fluxx/addon/ReactConnector';
import store1 from './store1';
import store2 from './store2';
import MyComp from './myComponent';

var instance = (
<Fluxx stores={[store1, store2]}>{ (one, two) =>
<MyComp
propOne={one}
propTwo={two}
/>
}
</Fluxx>
);

// Or

var instance = (
<Fluxx stores={[store1, store2]}>
<MyComp/>
</Fluxx>
);

```


<a name="facebookImplementation"></a>
## Differences with the Facebook implementation

Expand All @@ -246,8 +286,12 @@ action.increment(33);

```javascript
dispatcher.waitFor([store1.dispatchToken, store2.dispatchToken])

// Becomes
dependOn(store1, store2)

dependOn: [store1, store2] // Store
// or
dependOn(store1, store2) // ActorStore
```

- Use closure-style modules instead of clumsy pseudo/es6 classes
Expand All @@ -257,7 +301,18 @@ dependOn(store1, store2)
## Enabling logging

This will log all action dispatching along with the list of stores that handled the action.
Note: For easier debugging, give proper names to your stores, e.g `var store = Store(function someName() {})`
Note: For easier debugging, give proper names to your stores, e.g:


```javascript
var store = Store({ name: 'myStore' });
```

Or

```javascript
var store = ActorStore(function someName() {})
```

```javascript
var fluxx = require('fluxx');
Expand All @@ -273,5 +328,5 @@ fluxx.enableLogs();

## Running the tests
```
mocha --ui tdd
npm run test
```
4 changes: 1 addition & 3 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,5 @@
"build": "NODE_ENV=production browserify src/main.js > bundle.js"
},

"browserify": {
"transform": ["babelify"]
}
"browserify": { "transform": ["babelify"] }
}
2 changes: 2 additions & 0 deletions example/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import MagicButton from './MagicButton';
export default React.createClass({

render: function() {
console.log('render');

return (
<div>
<MagicButton />
Expand Down
2 changes: 1 addition & 1 deletion example/src/blueNumber.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { init, decrement, increment } from './actions';


export default Store({
name: 'blueNumber',
name: 'blue',

state: 0,

Expand Down
20 changes: 9 additions & 11 deletions example/src/greenNumber.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import ActorStore from '../../src/ActorStore';
import Store from '../../src/Store';
import { init, decrement, increment } from './actions';
import blueNumber from './blueNumber';


// Here, ActorStore is used to compute a derived state; A stateless Store wouldn't do the job.
module.exports = ActorStore(function greenNumber(on) {
var currentOffset = 0;
export default Store({
name: 'green',

on(init);
on(decrement, offset => currentOffset -= (10 * offset));
on(increment, offset => currentOffset += (10 * offset));
state: 0,

return {
value: function() { return blueNumber.state + currentOffset }
};
handlers: {
[init]: (state, val) => val,
[increment]: (state, offset) => state + 10 * offset,
[decrement]: (state, offset) => state - 10 * offset
}
});
27 changes: 13 additions & 14 deletions example/src/main.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
import React from 'react';
import fluxx from '../../src/fluxx';
import blueNumber from './blueNumber';
import greenNumber from './greenNumber';
import redNumber from './redNumber';
import Fluxx from '../../src/addon/ReactConnector';
import blueStore from './blueNumber';
import greenStore from './greenNumber';
import redStore from './redNumber';
import App from './App';
import { init } from './actions';


function render() {
console.log('render');

return React.render(
React.render(
<Fluxx stores={[blueStore, greenStore, redStore]}>{ (blue, green, red) =>
<App
blueNumber={blueNumber.state}
greenNumber={greenNumber.value()}
redNumber={redNumber.state}/>,
blueNumber={blue}
greenNumber={green}
redNumber={red}/>
}
</Fluxx>,

document.querySelector('body')
);
}
document.querySelector('body')
);

fluxx.onChange(blueNumber, greenNumber, redNumber)(render);

fluxx.enableLogs();
init(10);
2 changes: 1 addition & 1 deletion example/src/redNumber.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { init, decrement, increment } from './actions';

// Matches blue number if blue number is increasing, else noop
export default Store({
name: 'redNumber',
name: 'red',

state: 0,

Expand Down
16 changes: 14 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fluxx",
"version": "0.8.1",
"version": "0.9.0",
"main": "src/fluxx",
"description": "Facebook flux-like Store, Action",
"keywords": ["flux", "facebook", "dispatcher", "store", "action", "reactive", "unidirectional"],
Expand All @@ -16,11 +16,23 @@
},

"dependencies": {
"events": "1.0.2"
"events": "1.0.2",
"babelify": "6.1.3"
},

"peerDependencies": {
"react": ">=0.13.0"
},

"devDependencies": {
"mocha-babel": "3.0.0",
"mocha": "2.1.0",
"better-assert": "1.0.1"
},

"browserify": { "transform": ["babelify"] },

"scripts": {
"test": "mocha --compilers js:mocha-babel --ui tdd"
}
}
13 changes: 4 additions & 9 deletions src/Action.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
'use strict';

var dispatcher = require('./dispatcher');
import dispatcher from './dispatcher';


var id = 1;
Expand All @@ -14,7 +12,7 @@ var id = 1;
* var ClickThread = Action('clickThread'); // Create the action once
* ClickThread(id); // Dispatch a payload any number of times
*/
function Action(name) {
export default function Action(name) {

function action() {
var payloads = [].slice.call(arguments);
Expand All @@ -33,11 +31,8 @@ function Action(name) {
* var actions = Action.create('clickThread', 'scroll');
*/
Action.create = function() {
return [].slice.call(arguments).reduce(function(obj, name) {
return [].slice.call(arguments).reduce((obj, name) => {
obj[name] = Action(name);
return obj;
}, {});
};


module.exports = Action;
};
Loading

0 comments on commit ac6db3d

Please sign in to comment.