From b830df5dbafd175e502c212ec686475ea6a0695c Mon Sep 17 00:00:00 2001 From: prescottprue Date: Thu, 29 Jun 2017 16:45:55 -0700 Subject: [PATCH 1/3] Connect added back. --- examples/complete/react-native/package.json | 2 +- examples/complete/react-native/src/Home.js | 6 +- examples/complete/react-native/yarn.lock | 84 +++++++------- src/connect.js | 120 ++++++++++++++++++++ src/index.js | 3 +- 5 files changed, 172 insertions(+), 43 deletions(-) create mode 100644 src/connect.js diff --git a/examples/complete/react-native/package.json b/examples/complete/react-native/package.json index 43708e3f7..b558a7607 100644 --- a/examples/complete/react-native/package.json +++ b/examples/complete/react-native/package.json @@ -14,7 +14,7 @@ "react-native": "0.42.0", "react-native-google-signin": "0.9.0", "react-redux": "^5.0.3", - "react-redux-firebase": "^1.4.0", + "react-redux-firebase": "^2.0.0-alpha.3", "redux": "^3.6.0" }, "devDependencies": { diff --git a/examples/complete/react-native/src/Home.js b/examples/complete/react-native/src/Home.js index 6e53caa3b..e88979d5b 100644 --- a/examples/complete/react-native/src/Home.js +++ b/examples/complete/react-native/src/Home.js @@ -1,6 +1,6 @@ import React, { Component } from 'react'; import { GoogleSignin, GoogleSigninButton } from 'react-native-google-signin'; -import { firebaseConnect, pathToJS, isLoaded } from 'react-redux-firebase'; +import { firebaseConnect } from 'react-redux-firebase'; import { connect } from 'react-redux'; import { AppRegistry, @@ -42,8 +42,8 @@ const styles = StyleSheet.create({ }); @firebaseConnect() -@connect(({ firebase }) => ({ - auth: pathToJS(firebase, 'auth') +@connect(({ firebase: { auth } }) => ({ + auth })) export default class SigninSampleApp extends Component { state = { diff --git a/examples/complete/react-native/yarn.lock b/examples/complete/react-native/yarn.lock index ab340016d..410133c80 100644 --- a/examples/complete/react-native/yarn.lock +++ b/examples/complete/react-native/yarn.lock @@ -1131,7 +1131,7 @@ detect-indent@^4.0.0: dependencies: repeating "^2.0.0" -dom-storage@2.0.2: +dom-storage@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/dom-storage/-/dom-storage-2.0.2.tgz#ed17cbf68abd10e0aef8182713e297c5e4b500b0" @@ -1187,9 +1187,9 @@ errorhandler@~1.4.2: accepts "~1.3.0" escape-html "~1.0.3" -es6-promise@^4.0.5: - version "4.1.0" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.1.0.tgz#dda03ca8f9f89bc597e689842929de7ba8cebdf0" +es6-promise@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.1.1.tgz#8811e90915d9a0dba36274f0b242dbda78f9c92a" escape-html@1.0.2: version "1.0.2" @@ -1279,7 +1279,7 @@ fbjs-scripts@^0.7.0: semver "^5.1.0" through2 "^2.0.0" -fbjs@^0.8.4, fbjs@^0.8.5: +fbjs@^0.8.4, fbjs@^0.8.5, fbjs@^0.8.9: version "0.8.9" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.9.tgz#180247fbd347dcc9004517b904f865400a0c8f14" dependencies: @@ -1314,15 +1314,15 @@ find-up@^1.0.0: path-exists "^2.0.0" pinkie-promise "^2.0.0" -firebase@3.7.1: - version "3.7.1" - resolved "https://registry.yarnpkg.com/firebase/-/firebase-3.7.1.tgz#8e10d18d79bde61c2379b31dffb73a9094aa9873" +firebase@^4.1.2, firebase@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/firebase/-/firebase-4.1.3.tgz#e5d7327366c854dc12461633ba8bfeea2f5c7358" dependencies: - dom-storage "2.0.2" + dom-storage "^2.0.2" faye-websocket "0.9.3" - jsonwebtoken "7.1.9" - rsvp "3.2.1" - xmlhttprequest "1.8.0" + jsonwebtoken "^7.3.0" + promise-polyfill "^6.0.2" + xmlhttprequest "^1.8.0" forever-agent@~0.6.1: version "0.6.1" @@ -1506,7 +1506,7 @@ hoek@2.x.x: version "2.16.3" resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" -hoist-non-react-statics@^1.0.3: +hoist-non-react-statics@^1.0.3, hoist-non-react-statics@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb" @@ -1552,10 +1552,6 @@ image-size@^0.3.5: version "0.3.5" resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.3.5.tgz#83240eab2fb5b00b04aab8c74b0471e9cba7ad8c" -immutable@^3.8.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.1.tgz#200807f11ab0f72710ea485542de088075f68cd2" - immutable@~3.7.6: version "3.7.6" resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b" @@ -1741,14 +1737,14 @@ jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" -jsonwebtoken@7.1.9: - version "7.1.9" - resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-7.1.9.tgz#847804e5258bec5a9499a8dc4a5e7a3bae08d58a" +jsonwebtoken@^7.3.0: + version "7.4.1" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-7.4.1.tgz#7ca324f5215f8be039cd35a6c45bb8cb74a448fb" dependencies: joi "^6.10.1" - jws "^3.1.3" + jws "^3.1.4" lodash.once "^4.0.0" - ms "^0.7.1" + ms "^2.0.0" xtend "^4.0.1" jsprim@^1.2.2: @@ -1768,7 +1764,7 @@ jwa@^1.1.4: ecdsa-sig-formatter "1.0.9" safe-buffer "^5.0.1" -jws@^3.1.3: +jws@^3.1.4: version "3.1.4" resolved "https://registry.yarnpkg.com/jws/-/jws-3.1.4.tgz#f9e8b9338e8a847277d6444b1464f61880e050a2" dependencies: @@ -1776,7 +1772,7 @@ jws@^3.1.3: jwa "^1.1.4" safe-buffer "^5.0.1" -jwt-decode@^2.1.0: +jwt-decode@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-2.2.0.tgz#7d86bd56679f58ce6a84704a657dd392bba81a79" @@ -1931,7 +1927,7 @@ longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" -loose-envify@^1.0.0, loose-envify@^1.1.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" dependencies: @@ -2039,10 +2035,14 @@ ms@0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" -ms@0.7.2, ms@^0.7.1: +ms@0.7.2: version "0.7.2" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" +ms@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + multimatch@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-2.1.0.tgz#9c7906a22fb4c02919e2f5f75161b4cdbd4b2a2b" @@ -2255,12 +2255,23 @@ process@~0.5.1: version "0.5.2" resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" +promise-polyfill@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-6.0.2.tgz#d9c86d3dc4dc2df9016e88946defd69b49b41162" + promise@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf" dependencies: asap "~2.0.3" +prop-types@^15.5.8: + version "15.5.10" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154" + dependencies: + fbjs "^0.8.9" + loose-envify "^1.3.1" + prr@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" @@ -2396,15 +2407,16 @@ react-proxy@^1.1.7: lodash "^4.6.1" react-deep-force-update "^1.0.0" -react-redux-firebase@^1.4.0-alpha: - version "1.4.0-alpha" - resolved "https://registry.yarnpkg.com/react-redux-firebase/-/react-redux-firebase-1.4.0-alpha.tgz#e5bba53af49d86eb93922d514fa8baec35155b89" +react-redux-firebase@^2.0.0-alpha.3: + version "2.0.0-alpha.3" + resolved "https://registry.yarnpkg.com/react-redux-firebase/-/react-redux-firebase-2.0.0-alpha.3.tgz#3f1ec43575f90a0415e0bdcf5d1dccc01a9f9a1f" dependencies: - es6-promise "^4.0.5" - firebase "3.7.1" - immutable "^3.8.1" - jwt-decode "^2.1.0" + es6-promise "^4.1.0" + firebase "^4.1.3" + hoist-non-react-statics "^1.2.0" + jwt-decode "^2.2.0" lodash "^4.17.4" + prop-types "^15.5.8" react-redux@^5.0.3: version "5.0.3" @@ -2612,10 +2624,6 @@ rndm@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/rndm/-/rndm-1.2.0.tgz#f33fe9cfb52bbfd520aa18323bc65db110a1b76c" -rsvp@3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" - run-async@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" @@ -3120,7 +3128,7 @@ xmldom@0.1.x: version "0.1.27" resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" -xmlhttprequest@1.8.0: +xmlhttprequest@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" diff --git a/src/connect.js b/src/connect.js new file mode 100644 index 000000000..db853dbf2 --- /dev/null +++ b/src/connect.js @@ -0,0 +1,120 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import { isEqual } from 'lodash' +import hoistStatics from 'hoist-non-react-statics' +import { watchEvents, unWatchEvents } from './actions/query' +import { getEventsFromInput, createCallable } from './utils' + +/** + * @name createFirebaseConnect + * @description WARNING!! Advanced feature, and only be used when needing to + * access a firebase instance created under a different store key + * @param {String} storeKey - Name of key of store to connect to (store that contains state.firebase) + * @return {Function} - that returns a firebaseConnect function, which is later used to wrap a component + * @example Data + * import { connect } from 'react-redux' + * import { createFirebaseConnect } from 'react-redux-firebase' + * + * // sync /todos from firebase (in other store) into redux + * const fbWrapped = createFirebaseConnect('someOtherName')(['todos']) + * + * // pass todos list from redux as this.props.todosList + * export default connect(({ firebase: data: { todos }, auth, profile }) => ({ + * todos, + * profile, // pass profile data as this.props.profile + * auth // pass auth data as this.props.auth + * }))(fbWrapped) + */ +export const createFirebaseConnect = (storeKey = 'store') => (dataOrFn = []) => WrappedComponent => { + /** + * @name firebaseConnect + * @extends React.Component + * @description Higher Order Component that automatically listens/unListens + * to provided firebase paths using React's Lifecycle hooks. + * @param {Array} watchArray - Array of objects or strings for paths to sync + * from Firebase. Can also be a function that returns the array. The function + * is passed the current props and the firebase object. + * @return {Function} - that accepts a component to wrap and returns the wrapped component + * @example Basic + * // this.props.firebase set on App component as firebase object with helpers + * import { firebaseConnect } from 'react-redux-firebase' + * export default firebaseConnect()(App) + * @example Data + * import { connect } from 'react-redux' + * import { firebaseConnect } from 'react-redux-firebase' + * + * // sync /todos from firebase into redux + * const fbWrapped = firebaseConnect([ + * 'todos' + * ])(App) + * + * // pass todos list from redux as this.props.todosList + * export default connect(({ firebase: data: { todos }, auth, profile }) => ({ + * todos, + * profile, // pass profile data as this.props.profile + * auth // pass auth data as this.props.auth + * }))(fbWrapped) + */ + class FirebaseConnect extends Component { + constructor (props, context) { + super(props, context) + this._firebaseEvents = [] + this.firebase = null + } + + static contextTypes = { + [storeKey]: PropTypes.object.isRequired + }; + + componentWillMount () { + const { firebase, dispatch } = this.context[storeKey] + + // Allow function to be passed + const inputAsFunc = createCallable(dataOrFn) + this.prevData = inputAsFunc(this.props, firebase) + + const { ref, helpers, storage, database, auth } = firebase + this.firebase = { ref, storage, database, auth, ...helpers } + + this._firebaseEvents = getEventsFromInput(this.prevData) + + watchEvents(firebase, dispatch, this._firebaseEvents) + } + + componentWillUnmount () { + const { firebase, dispatch } = this.context.store + unWatchEvents(firebase, dispatch, this._firebaseEvents) + } + + componentWillReceiveProps (np) { + const { firebase, dispatch } = this.context.store + const inputAsFunc = createCallable(dataOrFn) + const data = inputAsFunc(np, firebase) + + // Handle a data parameter having changed + if (!isEqual(data, this.prevData)) { + this.prevData = data + // UnWatch all current events + unWatchEvents(firebase, dispatch, this._firebaseEvents) + // Get watch events from new data + this._firebaseEvents = getEventsFromInput(data) + // Watch new events + watchEvents(firebase, dispatch, this._firebaseEvents) + } + } + + render () { + return ( + + ) + } + } + + return hoistStatics(FirebaseConnect, WrappedComponent) +} + +export default createFirebaseConnect() diff --git a/src/index.js b/src/index.js index d2ecf0d7a..b8f4b5eb9 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,5 @@ -import firebaseConnect, { createFirebaseInstance } from './createFirebaseInstance' +import { createFirebaseInstance } from './createFirebaseInstance' +import firebaseConnect from './connect' import compose, { getFirebase } from './compose' import reducer from './reducer' import constants, { actionTypes } from './constants' From 403a8ae4385c8e0ebd8985e406755c52e374b2f8 Mon Sep 17 00:00:00 2001 From: prescottprue Date: Thu, 29 Jun 2017 16:50:50 -0700 Subject: [PATCH 2/3] Version bump. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 772dee29a..d8b8d3932 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-redux-firebase", - "version": "2.0.0-alpha.3", + "version": "2.0.0-alpha.4", "description": "Redux integration for Firebase. Comes with a Higher Order Component for use with React.", "main": "lib/index.js", "module": "es/index.js", From 96e4eaf8097ee2c508dde0466e4188821e6ce953 Mon Sep 17 00:00:00 2001 From: prescottprue Date: Thu, 29 Jun 2017 17:11:15 -0700 Subject: [PATCH 3/3] createFirebaseConnect exposed --- src/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index b8f4b5eb9..1f1c8ef32 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,5 @@ import { createFirebaseInstance } from './createFirebaseInstance' -import firebaseConnect from './connect' +import firebaseConnect, { createFirebaseConnect } from './connect' import compose, { getFirebase } from './compose' import reducer from './reducer' import constants, { actionTypes } from './constants' @@ -8,6 +8,7 @@ import * as helpers from './helpers' export default { firebase: firebaseConnect, firebaseConnect, + createFirebaseConnect, createFirebaseInstance, firebaseStateReducer: reducer, reduxReactFirebase: compose,