Skip to content

Commit 26bdbb9

Browse files
committed
Create a HoC as an alternative to the mixin
1 parent e7fddf4 commit 26bdbb9

File tree

4 files changed

+121
-3
lines changed

4 files changed

+121
-3
lines changed

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,8 @@
2525
"babel-eslint": "^4.1.7",
2626
"eslint": "^0.22.1",
2727
"mocha": "^2.2.5"
28+
},
29+
"peerDependencies": {
30+
"react": "^0.13.0 || ^0.14.0 || ^15.0.0"
2831
}
2932
}

src/HoC.js

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import React from 'react';
2+
import {ensure} from './util';
3+
import {update, unmount} from './Mixin';
4+
5+
// Mixin for RethinkDB query subscription support in React components. You'll
6+
// generally want to use DefaultHoC or PropsHoC, which use BaseHoC to
7+
// create more usable versions.
8+
//
9+
// Along with your component, you should pass an observe(props, state) function that
10+
// returns an object mapping query names to QueryRequests. See
11+
// QueryRequest.js for the API.
12+
//
13+
// In the child component, you will have access to this.props.data, which is an
14+
// object mapping from the same query names returned in observe() to the
15+
// results of each query as an QueryResult. See QueryResult.js for the
16+
// API.
17+
//
18+
// Here is a simple example of the mixin API:
19+
// const observe = (props) => ({
20+
// turtles: new QueryRequest({
21+
// query: r.table('turtles'),
22+
// changes: true,
23+
// initial: [],
24+
// }),
25+
// });
26+
27+
// class App extends Component {
28+
// render() {
29+
// return <div>
30+
// {this.props.data.turtles.value().map(function(x) {
31+
// return <div key={x.id}>{x.firstName}</div>;
32+
// })};
33+
// </div>;
34+
// },
35+
// };
36+
37+
// BaseHoC(() => new Session())(observe)(App);
38+
39+
export const BaseHoC = sessionGetter => observe => ChildComponent => class ReactRethinkDB extends React.Component {
40+
constructor(props) {
41+
super();
42+
this.observe = observe;
43+
}
44+
45+
componentWillMount() {
46+
const session = sessionGetter(this);
47+
this.runQuery = session.runQuery.bind(session);
48+
ensure(session && session._subscriptionManager, 'Must define Session');
49+
ensure(this.observe, 'Must define observe()');
50+
ensure(session._connPromise, 'Must connect() before mounting react-rethinkdb');
51+
this._rethinkMixinState = {session, subscriptions: {}};
52+
this.data = this.data || {};
53+
update(this, this.props);
54+
}
55+
56+
componentDidMount() {
57+
this._rethinkMixinState.isMounted = true;
58+
}
59+
60+
componentWillUnmount() {
61+
unmount(this);
62+
this._rethinkMixinState.isMounted = false;
63+
}
64+
65+
componentWillUpdate(nextProps) {
66+
if (nextProps !== this.props) {
67+
update(this, nextProps);
68+
}
69+
}
70+
71+
render() {
72+
return <ChildComponent data={this.data} runQuery={this.runQuery} {...this.props} />;
73+
}
74+
};
75+
76+
// Within ChildComponent, you can then run queries like this:
77+
// var App = React.createClass({
78+
// handleSubmit: function(event) {
79+
// event.preventDefault();
80+
// var { runQuery } = this.props
81+
// var nameInput = this.refs.firstName;
82+
// var query = r.table('turtles').insert({firstName: nameInput.value});
83+
// nameInput.value = '';
84+
// runQuery(query);
85+
// },
86+
87+
// render: function() {
88+
// var turtleDivs = this.data.turtles.value().map(function(x) {
89+
// return <div key={x.id}>{x.firstName}</div>;
90+
// });
91+
// return <div>
92+
// <form onSubmit={this.handleSubmit}>
93+
// <input type="text" ref="firstName" />
94+
// <input type="submit" />
95+
// </form>
96+
// {turtleDivs}
97+
// </div>;
98+
// },
99+
// });
100+
101+
// HoC that uses rethink session from props. For example:
102+
// class MyComponent extends Component {
103+
// ...
104+
// });
105+
// var session = new Session();
106+
// React.render(<MyComponent rethinkSession={session} />, mountNode);
107+
export const PropsHoC = name => BaseHoC(component => component.props[name]);

src/Mixin.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {QueryResult} from './QueryResult';
22
import {ensure} from './util';
33

4-
const update = (component, props, state) => {
4+
export const update = (component, props, state) => {
55
const observed = component.observe(props, state);
66
const {session, subscriptions} = component._rethinkMixinState;
77
const subscriptionManager = session._subscriptionManager;
@@ -27,7 +27,7 @@ const update = (component, props, state) => {
2727
});
2828
};
2929

30-
const unmount = component => {
30+
export const unmount = component => {
3131
const {subscriptions} = component._rethinkMixinState;
3232
Object.keys(subscriptions).forEach(key => {
3333
subscriptions[key].unsubscribe();

src/index.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import {BaseHoC, PropsHoC} from './HoC';
12
import {BaseMixin, PropsMixin} from './Mixin';
23
import {QueryRequest} from './QueryRequest';
34
import {MetaSession} from './Session';
@@ -12,24 +13,31 @@ const DefaultSession = new Session();
1213
// Singleton mixin for convenience, which uses the DefaultSession singleton as
1314
// the session.
1415
const DefaultMixin = BaseMixin(() => DefaultSession);
16+
const DefaultHoC = BaseHoC(() => DefaultSession);
1517

1618
const ReactRethinkdb = {
1719
BaseMixin,
1820
PropsMixin,
21+
BaseHoC,
22+
PropsHoC,
1923
QueryRequest,
2024
r,
2125
Session,
2226
DefaultSession,
23-
DefaultMixin
27+
DefaultMixin,
28+
DefaultHoC
2429
};
2530

2631
export {
2732
BaseMixin,
2833
PropsMixin,
34+
BaseHoC,
35+
PropsHoC,
2936
QueryRequest,
3037
r,
3138
Session,
3239
DefaultSession,
3340
DefaultMixin,
41+
DefaultHoC,
3442
ReactRethinkdb as default,
3543
};

0 commit comments

Comments
 (0)