-
Notifications
You must be signed in to change notification settings - Fork 48
/
Mixin.js
108 lines (99 loc) · 3.56 KB
/
Mixin.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import {QueryResult} from './QueryResult';
import {ensure} from './util';
const update = (component, props, state) => {
const observed = component.observe(props, state);
const {session, subscriptions} = component._rethinkMixinState;
const subscriptionManager = session._subscriptionManager;
// Close subscriptions no longer subscribed to
Object.keys(subscriptions).forEach(key => {
if (!observed[key]) {
subscriptions[key].unsubscribe();
delete component.data[key];
}
});
// [Re]-subscribe to active queries
Object.keys(observed).forEach(key => {
const queryRequest = observed[key];
const oldSubscription = subscriptions[key];
const queryResult = component.data[key] || new QueryResult(queryRequest.initial, queryRequest.transform);
subscriptions[key] = subscriptionManager.subscribe(component, queryRequest, queryResult);
component.data[key] = queryResult;
if (oldSubscription) {
oldSubscription.unsubscribe();
}
});
};
const unmount = component => {
const {subscriptions} = component._rethinkMixinState;
Object.keys(subscriptions).forEach(key => {
subscriptions[key].unsubscribe();
});
};
// Mixin for RethinkDB query subscription support in React components. You'll
// generally want to use DefaultMixin or PropsMixin, which use BaseMixin to
// create more usable versions.
//
// In your component, you should define an observe(props, state) method that
// returns an object mapping query names to QueryRequests. See
// QueryRequest.js for the API.
//
// In the render() function, you will have access to this.data, which is an
// object mapping from the same query names returned in observe() to the
// results of each query as an QueryResult. See QueryResult.js for the
// API.
//
// Here is a simple example of the mixin API:
// var App = React.createClass({
// mixins: [DefaultMixin],
//
// observe: function(props, state) {
// return {
// turtles: new QueryRequest({
// query: r.table('turtles'),
// changes: true,
// initial: [],
// }),
// };
// },
//
// render: function() {
// return <div>
// {this.data.turtles.value().map(function(x) {
// return <div key={x.id}>{x.firstName}</div>;
// })};
// </div>;
// },
// });
export const BaseMixin = sessionGetter => ({
componentWillMount() {
const componentName = this && this.constructor && this.constructor.displayName || '';
const session = sessionGetter(this);
ensure(session && session._subscriptionManager,
`Mixin in ${componentName} does not have Session`);
ensure(this.observe, `Must define ${componentName}.observe()`);
ensure(session._connPromise, `Must connect() before mounting ${componentName}`);
this._rethinkMixinState = {session, subscriptions: {}};
this.data = this.data || {};
update(this, this.props, this.state);
},
componentDidMount() {
this._rethinkMixinState.isMounted = true;
},
componentWillUnmount() {
unmount(this);
this._rethinkMixinState.isMounted = false;
},
componentWillUpdate(nextProps, nextState) {
if (nextProps !== this.props || nextState !== this.state) {
update(this, nextProps, nextState);
}
},
});
// Mixin that uses rethink session from props. For example:
// var MyComponent = React.createClass({
// mixins: [PropsMixin('rethinkSession')],
// ...
// });
// var session = new Session();
// React.render(<MyComponent rethinkSession={session} />, mountNode);
export const PropsMixin = name => BaseMixin(component => component.props[name]);