├── .flowconfig
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── declarations
└── jasmine.js
├── karma.conf.js
├── package.json
├── scripts
└── publish-to-npm.sh
├── src
├── _.js
├── create-fluce.js
├── fluce-component.js
├── index.js
├── reduce.js
└── types.js
└── test
├── _.spec.js
├── create-fluce.spec.js
├── fixtures.js
├── fluce-component.spec.js
├── helpers.js
└── reduce.spec.js
/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 | .*/enhanced-resolve/test/fixtures/node_modules/invalidPackageJson
3 | .*/phantomjs/node_modules/npmconf/test/fixtures/package.json
4 | .*/npm-pkg
5 |
6 | [include]
7 |
8 | [libs]
9 | declarations/
10 |
11 | [options]
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # node-waf configuration
20 | .lock-wscript
21 |
22 | # Compiled binary addons (http://nodejs.org/api/addons.html)
23 | build/Release
24 |
25 | # Dependency directory
26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
27 | node_modules
28 |
29 | npm-pkg
30 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | sudo: false
3 | before_script:
4 | - export DISPLAY=:99.0
5 | - sh -e /etc/init.d/xvfb start
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Roman Pominov
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Project status
2 |
3 | It's unfinished and frozen for now because of existence of a better alternative — [Redux](https://github.com/gaearon/redux)
4 |
5 | # Fluce
6 |
7 | [](https://david-dm.org/rpominov/fluce)
8 | [](https://david-dm.org/rpominov/fluce#info=devDependencies)
9 | [](https://travis-ci.org/rpominov/fluce)
10 | [](https://gitter.im/rpominov/fluce?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
11 |
12 | Well, Flux again ...
13 |
14 | - lib agnostic, but with helpers for React
15 | - forces to use immutable data structures in stores, or just never mutate
16 | - forces to use pure functions in stores
17 | - stores are just reducers of actions to their state
18 | - server-side ready
19 | - without singletons
20 |
21 | The name is combined from "flux" and "reduce".
22 |
23 |
24 | ## Installation
25 |
26 | ```
27 | $ npm install fluce
28 | ```
29 |
30 |
31 | ## Store
32 |
33 | Store in Fluce is just an object with the following shape:
34 |
35 | ```js
36 | {
37 | initial: Function,
38 | reducers: {
39 | foo: Function,
40 | bar: Function,
41 | ...
42 | }
43 | }
44 | ```
45 |
46 | Where `initial()` returns an initial _state_, and each of `reducers` is an action
47 | handler called with the current _state_ and the action's _payload_ as arguments
48 | returning a new _state_. Each reducer must be a pure function, that never
49 | mutate current state, but returns a new one instead. A reducer's name
50 | (e.g. `foo` above) is the action type that the reducer want to handle.
51 |
52 | ```js
53 | let myStore = {
54 | initial() {
55 | return myInitialState;
56 | },
57 | reducers: {
58 | actionType1(currentStoreState, actionPayload) {
59 | return computeNewState(currentStoreState, actionPayload);
60 | },
61 | actionType2(currentStoreState, actionPayload) {
62 | /* ... */
63 | }
64 | }
65 | };
66 | ```
67 |
68 |
69 | ## Fluce instance
70 |
71 | You start use Fluce by creating an instance of it. Normally you want
72 | only one instance in the browser, but may want to create an instance
73 | for each request on the server.
74 |
75 | ```js
76 | let createFluce = require('fluce/create-fluce');
77 |
78 | let fluce = createFluce();
79 | ```
80 |
81 | When an instance is created, you can add stores to it:
82 |
83 | ```js
84 | fluce.addStore('storeName1', myStore1);
85 | fluce.addStore('storeName2', myStore2);
86 | ```
87 |
88 | After this is done, you can access each store's current state as `fluce.stores.storeName`,
89 | and dispatch actions with `fluce.dispatch('actionType', payload)`.
90 | Also you can subscribe to changes of stores' states:
91 |
92 | ```js
93 | let unsubscribe = fluce.subscribe(['storeName1', 'storeName2'], (updatedStoresNames) => {
94 | // you can read new state directly from `fluce.stores.storeName`
95 | });
96 |
97 | // later...
98 | unsubscribe();
99 | ```
100 |
101 | Callback is called when some of specified stores change their state (via a reducer).
102 | If two or more stores change in response to a single action, the callback will
103 | be called only once. Also if a reducer returns same state, the store will be
104 | considered not changed.
105 |
106 |
107 | ## Example
108 |
109 | ```js
110 | let createFluce = require('fluce/create-fluce');
111 |
112 |
113 | // Setup
114 |
115 | let fluce = createFluce();
116 |
117 | fluce.addStore('counter', {
118 | initial() {
119 | return 0;
120 | },
121 | reducers: {
122 | counterAdd(cur, x) {
123 | return cur + x;
124 | },
125 | counterSubtract(cur, x) {
126 | return cur - x;
127 | }
128 | }
129 | });
130 |
131 | fluce.addStore('counterInverted', {
132 | initial() {
133 | return 0;
134 | },
135 | reducers: {
136 | counterAdd(cur, x) {
137 | return cur - x;
138 | },
139 | counterSubtract(cur, x) {
140 | return cur + x;
141 | }
142 | }
143 | });
144 |
145 |
146 | // Usage
147 |
148 | console.log(fluce.stores.counter); // => 0
149 | console.log(fluce.stores.counterInverted); // => 0
150 |
151 | fluce.actions.dispatch('counterAdd', 10);
152 |
153 | console.log(fluce.stores.counter); // => 10
154 | console.log(fluce.stores.counterInverted); // => -10
155 |
156 | fluce.subscribe(['counter', 'counterInverted'], (updated) => {
157 | console.log('following stores have updated:', updated);
158 | });
159 |
160 | fluce.actions.dispatch('counterSubtract', 5);
161 | // => following stores have updated: ['counter', 'counterInverted']
162 | ```
163 |
164 |
165 | # In progress
166 |
167 | The features below aren't done yet.
168 |
169 | ## <Fluce /> React component
170 |
171 | `` is an helper component, you can use to subscribe to stores and
172 | fire actions from a component that know nothing about Fluce. It outputs nothing
173 | but it's child component to the result DOM. It can have only one child, and
174 | renders it with a bit of a magic (adds more props to it).
175 |
176 | `` accepts following props:
177 |
178 | - `fluce` — the Fluce instance to use, the property is optional if there is another `` up the tree with this property specified.
179 | - `stores` — object of the shape `{foo: 'storeName', bar: 'anotherStoreName', ...}`, containing name of stores from which you want to read.
180 | Current state of each of these stores will be always available on the child component's props (`foo` and `bar` are the props names).
181 | - `actionCreators` — object of shape `{foo: (fluce, arg1, agr2) => {...}, ...}`, containing action creators that will be available as props on the child component. You will be able to call them like this `this.props.foo(arg1, agr2)` (without providing the first argument `fluce` — an instance of Fluce).
182 | - `render` — a custom render function you can provide, that will be used instead of simply render child with additional props.
183 |
184 |
185 | ```js
186 | let Fluce = require('fluce/fluce-component');
187 |
188 | class Counter extends React.Component {
189 | render() {
190 |
191 | // Also `this.props.fluce` will be available here,
192 | // but you shouldn't need it in most cases.
193 |
194 | return