diff --git a/package.json b/package.json index 859a29b..f61f5f3 100644 --- a/package.json +++ b/package.json @@ -25,5 +25,8 @@ "babel-eslint": "^4.1.7", "eslint": "^0.22.1", "mocha": "^2.2.5" + }, + "peerDependencies": { + "react": "^0.14.0 || ^15.0.0" } } diff --git a/src/HoC.js b/src/HoC.js new file mode 100644 index 0000000..bfb5ef0 --- /dev/null +++ b/src/HoC.js @@ -0,0 +1,83 @@ +import React from 'react'; +import {ensure} from './util'; +import {update, unmount} from './Mixin'; + +// Mixin for RethinkDB query subscription support in React components. You'll +// generally want to use DefaultHoC or PropsHoC, which use BaseHoC to +// create more usable versions. +// +// In your component, you should define an observe(props, state) function that +// returns an object mapping query names to QueryRequests. See +// QueryRequest.js for the API. +// +// In the child component, you will have access to this.props.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: +// const observe = (props, state) => ({ +// turtles: new QueryRequest({ +// query: r.table('turtles'), +// changes: true, +// initial: [], +// }), +// }); + +// class App extends Component { +// render() { +// return
+// {this.props.data.turtles.value().map(function(x) { +// return
{x.firstName}
; +// })}; +//
; +// }, +// }; + +// BaseHoC(new Session())(observe)(App); + +export const BaseHoC = sessionGetter => observe => ChildComponent => class ReactRethinkDB extends React.Component { + constructor(props, state) { + super(); + this.observe = observe; + } + + componentWillMount() { + const session = sessionGetter(this); + this.dispatch = session.runQuery.bind(session); + ensure(session && session._subscriptionManager, + `Must define Session`); + ensure(this.observe, `Must define observe()`); + ensure(session._connPromise, `Must connect() before mounting react-rethinkdb`); + 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); + } + } + + render() { + return ; + } +}; + +// HoC that uses rethink session from props. For example: +// class MyComponent extends Component { +// ... +// }); +// var session = new Session(); +// React.render(, mountNode); +export const PropsHoC = name => BaseHoC(component => component.props[name]); diff --git a/src/Mixin.js b/src/Mixin.js index d22258d..9af5a47 100644 --- a/src/Mixin.js +++ b/src/Mixin.js @@ -1,7 +1,7 @@ import {QueryResult} from './QueryResult'; import {ensure} from './util'; -const update = (component, props, state) => { +export const update = (component, props, state) => { const observed = component.observe(props, state); const {session, subscriptions} = component._rethinkMixinState; const subscriptionManager = session._subscriptionManager; @@ -27,7 +27,7 @@ const update = (component, props, state) => { }); }; -const unmount = component => { +export const unmount = component => { const {subscriptions} = component._rethinkMixinState; Object.keys(subscriptions).forEach(key => { subscriptions[key].unsubscribe(); diff --git a/src/index.js b/src/index.js index fd62243..c460a04 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,4 @@ +import {BaseHoC, PropsHoC} from './HoC'; import {BaseMixin, PropsMixin} from './Mixin'; import {QueryRequest} from './QueryRequest'; import {MetaSession} from './Session'; @@ -12,24 +13,31 @@ const DefaultSession = new Session(); // Singleton mixin for convenience, which uses the DefaultSession singleton as // the session. const DefaultMixin = BaseMixin(() => DefaultSession); +const DefaultHoC = BaseHoC(() => DefaultSession); const ReactRethinkdb = { BaseMixin, PropsMixin, + BaseHoC, + PropsHoC, QueryRequest, r, Session, DefaultSession, - DefaultMixin + DefaultMixin, + DefaultHoC }; export { BaseMixin, PropsMixin, + BaseHoC, + PropsHoC, QueryRequest, r, Session, DefaultSession, DefaultMixin, + DefaultHoC, ReactRethinkdb as default, };