diff --git a/docs/api/mixins/AsyncState.md b/docs/api/mixins/AsyncState.md deleted file mode 100644 index 7f1aa1f9cb..0000000000 --- a/docs/api/mixins/AsyncState.md +++ /dev/null @@ -1,120 +0,0 @@ -API: `AsyncState` (mixin) -========================= - -**WARNING**: This API is not going to be around much longer, don't use -it. We are taking a different approach that will be added very soon. - -So, anyway, you may continue... - -A mixin for route handlers that fetch at least part of their state -asynchronously. - -Static Lifecycle Methods ------------------------- - -### `getInitialAsyncState(params, query, setState)` - -Fetches state for a component after it mounts. Much like the familiar -`getInitialState` method, `getInitialAsyncState` should return a hash of -key/value pairs to use in the component's state. The difference is that -the values may be promises. As these values resolve, the component's -state is updated. - -#### Parameters - -##### params (object) - -The url parameters. - -##### query (object) - -The url query parameters - -##### setState (function) - -A function that can be used to `setState` as it is received, useful for -things like `xhr` progress and streamed data. Typically you won't use -this. - -Props ------ - -### `initialAsyncState` - -When testing, use the `initialAsyncState` prop to simulate asynchronous -data fetching. When this prop is present, no attempt is made to retrieve -additional state via `getInitialAsyncState`. - -Examples --------- - -In it simplest form, just return a hash of promises, they become state: - -```js -var User = React.createClass({ - mixins: [ Router.AsyncState ], - - statics: { - getInitialAsyncState: function (params, query, setState) { - return { - user: fetchUser(params.userId), - activity: fetchActivityForUser(params.userId) - } - } - }, - - render: function() { - return this.state.user ? - : - ; - } -}); -``` - -But you can get fancier... - -```js -var User = React.createClass({ - mixins: [ Router.AsyncState ], - - statics: { - getInitialAsyncState: function (params, query, setState) { - var buffer = ''; - - return { - user: getUserByID(params.userID) // may be a promise - activity: {}, // an immediate value (not a promise) - stream: getStreamingData(params.userID, function (chunk) { - // `getStreamingData` returns a promise, but also calls back as - // data is received, giving us a chance to update the UI with - // progress using the `AsyncState` specific `setState` - // function - buffer += chunk; - setState({ streamBuffer: buffer }); - }) - }; - } - }, - - getInitialState: function () { - return { - user: null, // Receives a value when getUserByID resolves. - stream: null, // Receives a value when getStreamingData resolves. - streamBuffer: '' // Used to track data as it loads. - }; - }, - - render: function () { - if (!this.state.user) - return ; - - return ( -
-

Welcome {this.state.user.name}!

-

So far, you've received {this.state.streamBuffer.length} data!

-
- ); - } -}); -``` - diff --git a/modules/index.js b/modules/index.js index e11a2565f5..62f052329a 100644 --- a/modules/index.js +++ b/modules/index.js @@ -6,6 +6,5 @@ exports.Route = require('./components/Route'); exports.Routes = require('./components/Routes'); exports.ActiveState = require('./mixins/ActiveState'); -exports.AsyncState = require('./mixins/AsyncState'); // TODO: Remove. exports.CurrentPath = require('./mixins/CurrentPath'); exports.Navigation = require('./mixins/Navigation'); diff --git a/modules/mixins/AsyncState.js b/modules/mixins/AsyncState.js deleted file mode 100644 index 71dbfed3df..0000000000 --- a/modules/mixins/AsyncState.js +++ /dev/null @@ -1,108 +0,0 @@ -var React = require('react'); -var resolveAsyncState = require('../utils/resolveAsyncState'); - -/** - * A mixin for route handler component classes that fetch at least - * part of their state asynchronously. Classes that use it should - * declare a static `getInitialAsyncState` method that fetches state - * for a component after it mounts. This function is given three - * arguments: 1) the current route params, 2) the current query and - * 3) a function that can be used to set state as it is received. - * - * Much like the familiar `getInitialState` method, `getInitialAsyncState` - * should return a hash of key/value pairs to use in the component's - * state. The difference is that the values may be promises. As these - * values resolve, the component's state is updated. You should only - * ever need to use the setState function for doing things like - * streaming data and/or updating progress. - * - * Example: - * - * var User = React.createClass({ - * - * statics: { - * - * getInitialAsyncState: function (params, query, setState) { - * // Return a hash with keys named after the state variables - * // you want to set, as you normally do in getInitialState, - * // except the values may be immediate values or promises. - * // The state is automatically updated as promises resolve. - * return { - * user: getUserByID(params.userID) // may be a promise - * }; - * - * // Or, use the setState function to stream data! - * var buffer = ''; - * - * return { - * - * // Same as above, the stream state variable is set to the - * // value returned by this promise when it resolves. - * stream: getStreamingData(params.userID, function (chunk) { - * buffer += chunk; - * - * // Notify of progress. - * setState({ - * streamBuffer: buffer - * }); - * }) - * - * }; - * } - * - * }, - * - * getInitialState: function () { - * return { - * user: null, // Receives a value when getUserByID resolves. - * stream: null, // Receives a value when getStreamingData resolves. - * streamBuffer: '' // Used to track data as it loads. - * }; - * }, - * - * render: function () { - * if (!this.state.user) - * return ; - * - * return ( - *
- *

Welcome {this.state.user.name}!

- *

So far, you've received {this.state.streamBuffer.length} data!

- *
- * ); - * } - * - * }); - * - * When testing, use the `initialAsyncState` prop to simulate asynchronous - * data fetching. When this prop is present, no attempt is made to retrieve - * additional state via `getInitialAsyncState`. - */ -var AsyncState = { - - propTypes: { - initialAsyncState: React.PropTypes.object - }, - - getInitialState: function () { - return this.props.initialAsyncState || null; - }, - - updateAsyncState: function (state) { - if (this.isMounted()) - this.setState(state); - }, - - componentDidMount: function () { - if (this.props.initialAsyncState || typeof this.constructor.getInitialAsyncState !== 'function') - return; - - resolveAsyncState( - this.constructor.getInitialAsyncState(this.props.params, this.props.query, this.updateAsyncState), - this.updateAsyncState - ); - } - -}; - -module.exports = AsyncState; diff --git a/modules/mixins/__tests__/AsyncState-test.js b/modules/mixins/__tests__/AsyncState-test.js deleted file mode 100644 index 7344987bc3..0000000000 --- a/modules/mixins/__tests__/AsyncState-test.js +++ /dev/null @@ -1,53 +0,0 @@ -var expect = require('expect'); -var React = require('react/addons'); -var ReactTestUtils = React.addons.TestUtils; -var Promise = require('../../utils/Promise'); -var AsyncState = require('../AsyncState'); - -describe('AsyncState', function () { - - describe('a component that fetches part of its state asynchronously', function () { - var User = React.createClass({ - mixins: [ AsyncState ], - statics: { - getInitialAsyncState: function (params, query, setState) { - setState({ - immediateValue: 'immediate' - }); - - setTimeout(function () { - setState({ - delayedValue: 'delayed' - }); - }); - - return { - promisedValue: Promise.resolve('promised') - }; - } - }, - render: function () { - return null; - } - }); - - var component; - beforeEach(function () { - component = ReactTestUtils.renderIntoDocument(User()); - }); - - afterEach(function () { - React.unmountComponentAtNode(component.getDOMNode()); - }); - - it('resolves all state variables correctly', function (done) { - setTimeout(function () { - expect(component.state.immediateValue).toEqual('immediate'); - expect(component.state.delayedValue).toEqual('delayed'); - expect(component.state.promisedValue).toEqual('promised'); - done(); - }, 20); - }); - }); - -}); diff --git a/modules/utils/resolveAsyncState.js b/modules/utils/resolveAsyncState.js deleted file mode 100644 index effb050d65..0000000000 --- a/modules/utils/resolveAsyncState.js +++ /dev/null @@ -1,25 +0,0 @@ -var Promise = require('when/lib/Promise'); - -/** - * Resolves all values in asyncState and calls the setState - * function with new state as they resolve. Returns a promise - * that resolves after all values are resolved. - */ -function resolveAsyncState(asyncState, setState) { - if (asyncState == null) - return Promise.resolve(); - - var keys = Object.keys(asyncState); - - return Promise.all( - keys.map(function (key) { - return Promise.resolve(asyncState[key]).then(function (value) { - var newState = {}; - newState[key] = value; - setState(newState); - }); - }) - ); -} - -module.exports = resolveAsyncState; diff --git a/tests.js b/tests.js index 5b159d1f00..0ce98464f3 100644 --- a/tests.js +++ b/tests.js @@ -4,7 +4,6 @@ require('./modules/components/__tests__/NotFoundRoute-test'); require('./modules/components/__tests__/Routes-test'); require('./modules/mixins/__tests__/ActiveContext-test'); -require('./modules/mixins/__tests__/AsyncState-test'); require('./modules/mixins/__tests__/LocationContext-test'); require('./modules/mixins/__tests__/Navigation-test'); require('./modules/mixins/__tests__/RouteContext-test');