|
| 1 | +var React = require('react'); |
| 2 | +var resolveAsyncState = require('../helpers/resolveAsyncState'); |
| 3 | + |
| 4 | +/** |
| 5 | + * A mixin for route handler component classes that fetch at least |
| 6 | + * part of their state asynchronously. Classes that use it should |
| 7 | + * declare a static `getInitialAsyncState` method that fetches state |
| 8 | + * for a component after it mounts. This function is given three |
| 9 | + * arguments: 1) the current route params, 2) the current query and |
| 10 | + * 3) a function that can be used to set state as it is received. |
| 11 | + * |
| 12 | + * Example: |
| 13 | + * |
| 14 | + * var User = React.createClass({ |
| 15 | + * |
| 16 | + * statics: { |
| 17 | + * |
| 18 | + * getInitialAsyncState: function (params, query, setState) { |
| 19 | + * // If you don't need to do anything async, just update |
| 20 | + * // the state immediately and you're done. |
| 21 | + * setState({ |
| 22 | + * user: UserStore.getUserByID(params.userID) |
| 23 | + * }); |
| 24 | + * |
| 25 | + * // Or, ignore the setState argument entirely and return a |
| 26 | + * // hash with keys named after the state variables you want |
| 27 | + * // to set. The values may be immediate values or promises. |
| 28 | + * return { |
| 29 | + * user: getUserByID(params.userID) // may be a promise |
| 30 | + * }; |
| 31 | + * |
| 32 | + * // Or, stream your data! |
| 33 | + * var buffer = ''; |
| 34 | + * |
| 35 | + * return { |
| 36 | + * |
| 37 | + * // Same as above, the stream state variable is set to the |
| 38 | + * // value returned by this promise when it resolves. |
| 39 | + * stream: getStreamingData(params.userID, function (chunk) { |
| 40 | + * buffer += chunk; |
| 41 | + * |
| 42 | + * // Notify of progress. |
| 43 | + * setState({ |
| 44 | + * streamBuffer: buffer |
| 45 | + * }); |
| 46 | + * }) |
| 47 | + * |
| 48 | + * }; |
| 49 | + * } |
| 50 | + * |
| 51 | + * }, |
| 52 | + * |
| 53 | + * getInitialState: function () { |
| 54 | + * return { |
| 55 | + * user: null, // Receives a value when getUserByID resolves. |
| 56 | + * stream: null, // Receives a value when getStreamingData resolves. |
| 57 | + * streamBuffer: '' // Used to track data as it loads. |
| 58 | + * }; |
| 59 | + * }, |
| 60 | + * |
| 61 | + * render: function () { |
| 62 | + * if (!this.state.user) |
| 63 | + * return <LoadingUser/>; |
| 64 | + * |
| 65 | + * return ( |
| 66 | + * <div> |
| 67 | + * <p>Welcome {this.state.user.name}!</p> |
| 68 | + * <p>So far, you've received {this.state.streamBuffer.length} data!</p> |
| 69 | + * </div> |
| 70 | + * ); |
| 71 | + * } |
| 72 | + * |
| 73 | + * }); |
| 74 | + * |
| 75 | + * When testing, use the `initialAsyncState` prop to simulate asynchronous |
| 76 | + * data fetching. When this prop is present, no attempt is made to retrieve |
| 77 | + * additional state via `getInitialAsyncState`. |
| 78 | + */ |
| 79 | +var AsyncState = { |
| 80 | + |
| 81 | + propTypes: { |
| 82 | + initialAsyncState: React.PropTypes.object |
| 83 | + }, |
| 84 | + |
| 85 | + getInitialState: function () { |
| 86 | + return this.props.initialAsyncState || null; |
| 87 | + }, |
| 88 | + |
| 89 | + updateAsyncState: function (state) { |
| 90 | + if (this.isMounted()) |
| 91 | + this.setState(state); |
| 92 | + }, |
| 93 | + |
| 94 | + componentDidMount: function () { |
| 95 | + if (this.props.initialAsyncState || !this.constructor.getInitialAsyncState) |
| 96 | + return; |
| 97 | + |
| 98 | + resolveAsyncState( |
| 99 | + this.constructor.getInitialAsyncState(this.props.params, this.props.query, this.updateAsyncState), |
| 100 | + this.updateAsyncState |
| 101 | + ); |
| 102 | + } |
| 103 | + |
| 104 | +}; |
| 105 | + |
| 106 | +module.exports = AsyncState; |
0 commit comments