diff --git a/README.md b/README.md
index 8cdcc0e..a10b538 100644
--- a/README.md
+++ b/README.md
@@ -5,37 +5,36 @@ state trooper
# Example Usage
-Call `StateTrooper.patrol` in your route handler/main app entry point
+Call `StateTrooper.patrolRunLoop` in your route handler/main app entry point
```javascript
-go(function*() {
- let component = React.renderComponent(
- ,
- document.querySelector('body')
- );
- const cursorChan = StateTrooper.patrol({
- // describe the state for the page
- state: {
- serverReport: null,
- bio: null,
- activity: null
- },
-
- // describe the fetchers and persisters for each piece of state
- // fetchers and persisters are functions that should return channels
- dataStore: {
- 'serverReport': { fetcher: serverReportFetcher },
- 'bio': { fetcher: bioFetcher, persister: bioPersister },
- 'activity': { fetcher: activityFetcher }
- }
- });
+const config = {
+ // describe the state for the page
+ state: {
+ serverReport: null,
+ bio: null,
+ activity: null
+ },
- let cursor;
- while(cursor = yield take(cursorChan)) {
- // update the component cursor prop everytime it changes
- component.setProps({ cursor: cursor });
+ // describe the fetchers and persisters for each piece of state
+ // fetchers and persisters are functions that should return channels
+ dataStore: {
+ 'serverReport': { fetcher: serverReportFetcher },
+ 'bio': { fetcher: bioFetcher, persister: bioPersister },
+ 'activity': { fetcher: activityFetcher }
}
+};
+const cursor = StateTrooper.patrolRunLoop(config, (cursor) => {
+ // Re-render the component when state changes generate new cursors
+ React.render(, document.querySelector('body'));
});
+
+// Render the component with the initial cursor
+React.render(
+ ,
+ document.querySelector('body')
+);
+
```
Using cursors inside of the components
diff --git a/package.json b/package.json
index 00e8db9..48cd005 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "state-trooper",
- "version": "2.0.0",
+ "version": "2.1.0",
"description": "Application State Manager",
"main": "index.js",
"types": "index.d.ts",
@@ -19,7 +19,7 @@
"homepage": "https://github.com/swipely/state-trooper",
"dependencies": {
"immutability-helper": "^2.2.0",
- "js-csp": "^0.5.0",
+ "js-csp": "0.9.2",
"lodash.isequal": "^4.5.0"
},
"devDependencies": {
diff --git a/src/run_update_loop.js b/src/run_update_loop.js
new file mode 100644
index 0000000..e76bb98
--- /dev/null
+++ b/src/run_update_loop.js
@@ -0,0 +1,20 @@
+import { go, poll, take } from 'js-csp';
+
+function runUpdateLoop(cursorCh, handleUpdate) {
+ const initialCursor = poll(cursorCh);
+
+ go(function* () {
+ let cursor;
+
+ while ((cursor = yield take(cursorCh))) {
+ // Allow the callback to exit the while loop
+ if (handleUpdate(cursor) === false) {
+ return;
+ }
+ }
+ });
+
+ return initialCursor;
+}
+
+export default runUpdateLoop;
diff --git a/src/state_trooper.js b/src/state_trooper.js
index 15c4b50..129948e 100644
--- a/src/state_trooper.js
+++ b/src/state_trooper.js
@@ -1,10 +1,17 @@
import getStateByPath from './get_state_by_path';
import patrol from './patrol';
import { stakeoutAt } from './stakeout';
+import runUpdateLoop from './run_update_loop';
+
+function patrolRunLoop(config, updateHandler) {
+ // Start an update loop using the channel created by patrol()
+ return runUpdateLoop(patrol(config), updateHandler);
+}
const StateTrooper = {
getStateByPath: getStateByPath,
patrol: patrol,
+ patrolRunLoop: patrolRunLoop,
stakeout: stakeoutAt
};
diff --git a/test/state_trooper_test.js b/test/state_trooper_test.js
index e844ce5..92dade2 100644
--- a/test/state_trooper_test.js
+++ b/test/state_trooper_test.js
@@ -36,7 +36,7 @@ describe('StateTrooper', function () {
it('puts a cursor on the cursor chan', function () {
go(function* () {
let cursor = yield take(cursorChan);
- expect( cursor.derefJS() ).to.eql({ foo: 'bar' });
+ expect( cursor.deref() ).to.eql({ foo: 'bar' });
});
});
@@ -68,6 +68,26 @@ describe('StateTrooper', function () {
});
});
+ describe('.patrolRunLoop', function () {
+ let config = {
+ state: {
+ foo: 'bar'
+ },
+ dataStore: {
+ 'foo': {
+ fetcher: sinon.spy(),
+ persister: sinon.spy()
+ }
+ }
+ };
+
+ it('returns the initial cursor', function () {
+ let cursor = StateTrooper.patrolRunLoop(config, (cursor) => {});
+ expect( cursor.deref() ).to.eql({ foo: 'bar' });
+ expect( config.dataStore['foo'].fetcher.calledOnce ).to.be(true);
+ });
+ });
+
describe('.stakeout', function () {
let cursorChan;