Skip to content

Commit 5a65c1e

Browse files
authored
Merge pull request #28 from cyclejs-community/run-userland
0.3.0 - Export drivers to userland
2 parents b249273 + 38e5eb5 commit 5a65c1e

File tree

7 files changed

+117
-78
lines changed

7 files changed

+117
-78
lines changed

CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# 0.3.0 - 2017-02-13
2+
3+
**BREAKING CHANGES**
4+
- `createCycleMiddleware()` no longer takes any arguments. Instead you need to call `Cycle.run` yourself (which can be installed via `npm i -s @cycle/xstream-run`) passing it your `main` function and `drivers` explicitly:
5+
6+
```diff
7+
+import {run} from '@cycle/xstream-run';
8+
9+
-const cycleMiddleware = createCycleMiddleware(main, drivers);
10+
+const cycleMiddleware = createCycleMiddleware();
11+
+const { makeActionDriver, makeStateDriver } = cycleMiddleware;
12+
13+
const store = createStore(
14+
rootReducer,
15+
applyMiddleware(cycleMiddleware)
16+
);
17+
18+
+run(main, {
19+
+ ACTION: makeActionDriver(),
20+
+ STATE: makeStateDriver()
21+
+})
22+
```
23+
24+
`createCycleMiddleware()` apart from returning the middleware function, also has two function properties attached to it; namely the `makeActionDriver()` and the `makeStateDriver()` which you can use accordingly when you call `Cycle.run`.

README.md

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@ Handle redux async actions using [Cycle.js](https://cycle.js.org/).
3030

3131
`npm install --save redux-cycles`
3232

33-
Then use `createCycleMiddleware()` which takes as first argument your `main` Cycle.js function, and second argument the Cycle.js drivers you want to use:
33+
Then use `createCycleMiddleware()` which returns the redux middleware function, but also has two function properties attached to it; namely `makeActionDriver()` and `makeStateDriver()` which you can use accordingly when you call `Cycle.run` (which can be installed via `npm i -s @cycle/xstream-run`).
3434

3535
```js
36+
import { run } from '@cycle/xstream-run';
3637
import { createCycleMiddleware } from 'redux-cycles';
3738

3839
function main(sources) {
@@ -45,17 +46,22 @@ function main(sources) {
4546
}
4647
}
4748

48-
const cycleMiddleware = createCycleMiddleware(main);
49+
const cycleMiddleware = createCycleMiddleware();
50+
const { makeActionDriver } = cycleMiddleware;
4951

5052
const store = createStore(
5153
rootReducer,
5254
applyMiddleware(cycleMiddleware)
5355
);
56+
57+
run(main, {
58+
ACTION: makeActionDriver()
59+
})
5460
```
5561

5662
## Example
5763

58-
Try out this [JS Bin](https://jsbin.com/govola/10/edit?js,output).
64+
Try out this [JS Bin](https://jsbin.com/bomugapuxi/2/edit?js,output).
5965

6066
See a real world example: [cycle autocomplete](https://github.com/cyclejs-community/redux-cycles/blob/master/example/cycle/index.js).
6167

@@ -242,8 +248,8 @@ This middleware intercepts Redux actions and allows us to handle them using Cycl
242248

243249
Redux-cycles ships with two drivers:
244250

245-
* `ACTION`, which is a read-write driver, allowing to react to actions that have just happened, as well as to dispatch new actions.
246-
* `STATE`, which is a read-only driver that streams the current redux state. It's a reactive counterpart of the `yield select(state => state)` effect in Redux-saga.
251+
* `makeActionDriver()`, which is a read-write driver, allowing to react to actions that have just happened, as well as to dispatch new actions.
252+
* `makeStateDriver()`, which is a read-only driver that streams the current redux state. It's a reactive counterpart of the `yield select(state => state)` effect in Redux-saga.
247253

248254
```javascript
249255
import sampleCombine from 'xstream/extra/sampleCombine'
@@ -263,21 +269,8 @@ function main(sources) {
263269
}
264270
```
265271

266-
Here's an example on [how the STATE driver works](https://jsbin.com/kijucaw/7/edit?js,output).
267-
268-
NOTE: If you want to use any other driver aside ACTION and STATE, make sure to have it installed and registered. You can do so at instantiation time, via the `createCycleMiddleware` API.
269-
For example, for the HTTP driver:
270-
271-
```bash
272-
npm install @cycle/http
273-
```
274-
275-
```javascript
276-
import { createCycleMiddleware } from 'redux-cycles';
277-
import { makeHTTPDriver } from '@cycle/http';
272+
Here's an example on [how the STATE driver works](https://jsbin.com/rohomaxuma/2/edit?js,output).
278273

279-
const cycleMiddleware = createCycleMiddleware(main, { HTTP: makeHTTPDriver() });
280-
```
281274
## Utils
282275

283276
### `combineCycles`

example/configureStore.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@ import { routerMiddleware } from 'react-router-redux';
44
import rootReducer from './reducers';
55
import main from './cycle';
66
import { createCycleMiddleware } from 'redux-cycles';
7+
import {run} from '@cycle/xstream-run';
78
import {makeHTTPDriver} from '@cycle/http';
89
import {timeDriver} from '@cycle/time';
910

10-
const cycleMiddleware = createCycleMiddleware(main, {
11-
Time: timeDriver,
12-
HTTP: makeHTTPDriver()
13-
});
14-
1511
export default function configureStore() {
12+
const cycleMiddleware = createCycleMiddleware();
13+
const { makeActionDriver, makeStateDriver } = cycleMiddleware;
14+
1615
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
1716
const store = createStore(
1817
rootReducer,
@@ -23,5 +22,13 @@ export default function configureStore() {
2322
)
2423
)
2524
);
25+
26+
run(main, {
27+
ACTION: makeActionDriver(),
28+
STATE: makeStateDriver(),
29+
Time: timeDriver,
30+
HTTP: makeHTTPDriver(),
31+
})
32+
2633
return store;
2734
}

example/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"react-router": "^2.6.1",
2323
"react-router-redux": "^4.0.5",
2424
"redux": "^3.5.2",
25-
"redux-cycles": "0.2.3",
25+
"redux-cycles": "file:../",
2626
"xstream": "^9.0.0"
2727
},
2828
"devDependencies": {

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "redux-cycles",
3-
"version": "0.2.3",
3+
"version": "0.3.0",
44
"description": "Bring functional reactive programming to Redux using Cycle.js",
55
"main": "dist",
66
"files": [
@@ -31,10 +31,10 @@
3131
},
3232
"license": "MIT",
3333
"dependencies": {
34-
"@cycle/xstream-run": "^4.0.0",
3534
"xstream": "^9.0.0"
3635
},
3736
"devDependencies": {
37+
"@cycle/xstream-run": "^4.0.0",
3838
"babel-cli": "^6.18.0",
3939
"babel-jest": "^18.0.0",
4040
"babel-preset-es2015": "^6.9.0",

src/createCycleMiddleware.js

Lines changed: 55 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,13 @@
1-
import {run} from '@cycle/xstream-run'
21
import xs from 'xstream'
32

4-
export default function createCycleMiddleware(mainFn, drivers = {}) {
5-
return store =>
6-
next => {
7-
let actionListener = null
8-
let stateListener = null
9-
10-
function actionDriver(outgoing$) {
11-
outgoing$.addListener({
12-
next: outgoing => {
13-
store.dispatch(outgoing)
14-
},
15-
error: () => {},
16-
complete: () => {},
17-
})
18-
19-
return xs.create({
20-
start: listener => {
21-
actionListener = listener
22-
},
23-
stop: () => {},
24-
})
25-
}
26-
27-
const isSame = {}
28-
const getCurrent = store.getState
29-
function stateDriver() {
30-
return xs.create({
31-
start: listener => {
32-
stateListener = listener
33-
},
34-
stop: () => {},
35-
})
36-
.fold((prevState, currState) => {
37-
if (prevState === getCurrent) {
38-
prevState = getCurrent()
39-
}
40-
if (prevState === currState) {
41-
return isSame
42-
}
43-
return currState
44-
}, getCurrent)
45-
.map(state => state === getCurrent ? getCurrent() : state)
46-
.filter(state => state !== isSame)
47-
}
48-
49-
drivers.ACTION = actionDriver
50-
drivers.STATE = stateDriver
51-
run(mainFn, drivers)
3+
export default function createCycleMiddleware () {
4+
let store = null
5+
let actionListener = null
6+
let stateListener = null
527

8+
const cycleMiddleware = _store => {
9+
store = _store
10+
return next => {
5311
return action => {
5412
let result = next(action)
5513
if (actionListener) {
@@ -61,4 +19,52 @@ export default function createCycleMiddleware(mainFn, drivers = {}) {
6119
return result
6220
}
6321
}
22+
}
23+
24+
cycleMiddleware.makeActionDriver = () => {
25+
return function actionDriver(outgoing$) {
26+
outgoing$.addListener({
27+
next: outgoing => {
28+
if (store) {
29+
store.dispatch(outgoing)
30+
}
31+
},
32+
error: () => {},
33+
complete: () => {},
34+
})
35+
36+
return xs.create({
37+
start: listener => {
38+
actionListener = listener
39+
},
40+
stop: () => {},
41+
})
42+
}
43+
}
44+
45+
cycleMiddleware.makeStateDriver = () => {
46+
const isSame = {}
47+
return function stateDriver() {
48+
const getCurrent = store.getState
49+
return xs.create({
50+
start: listener => {
51+
stateListener = listener
52+
},
53+
stop: () => {},
54+
})
55+
.fold((prevState, currState) => {
56+
if (prevState === getCurrent) {
57+
prevState = getCurrent()
58+
}
59+
if (prevState === currState) {
60+
return isSame
61+
}
62+
return currState
63+
}, getCurrent)
64+
.map(state => state === getCurrent ? getCurrent() : state)
65+
.filter(state => state !== isSame)
66+
}
67+
}
68+
69+
return cycleMiddleware
6470
}

test/createCycleMiddleware.test.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,24 @@
22
import { createCycleMiddleware } from '../'
33
import { createStore, applyMiddleware } from 'redux'
44
import xs from 'xstream'
5+
import {run} from '@cycle/xstream-run'
56
jest.useFakeTimers()
67

7-
function initStore(main, drivers, reducer = null) {
8+
function initStore(main, drivers, reducer = null, r = run) {
89
const rootReducer = reducer || ((state = [], action) => state.concat(action))
9-
const cycleMiddleware = createCycleMiddleware(main, drivers)
10+
11+
const cycleMiddleware = createCycleMiddleware()
12+
const { makeActionDriver, makeStateDriver } = cycleMiddleware
1013
const store = createStore(
1114
rootReducer,
1215
applyMiddleware(cycleMiddleware)
1316
)
17+
18+
r(main, {
19+
ACTION: makeActionDriver(),
20+
STATE: makeStateDriver()
21+
})
22+
1423
return store
1524
}
1625

0 commit comments

Comments
 (0)