Skip to content

Commit 3da16b7

Browse files
author
Scott Prue
committed
fix(HOCs): revert changes to firebaseConnect and firestoreConnect to preserve - #734
* fix(core): revert peer dependecy to 16.3.0 ([new context api](https://github.com/facebook/react/blob/master/CHANGELOG.md#1630-march-29-2018)) since only hooks require 16.8.0
1 parent 0bf01ac commit 3da16b7

File tree

3 files changed

+159
-54
lines changed

3 files changed

+159
-54
lines changed

package.json

+1-7
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,12 @@
5858
"redux-react-firebase"
5959
],
6060
"dependencies": {
61-
"gitbook-plugin-anchorjs": "^2.1.0",
62-
"gitbook-plugin-edit-link": "^2.0.2",
63-
"gitbook-plugin-ga": "^1.0.1",
64-
"gitbook-plugin-github": "^2.0.0",
65-
"gitbook-plugin-prism": "^2.4.0",
66-
"gitbook-plugin-versions-select": "^0.1.1",
6761
"hoist-non-react-statics": "^3.2.1",
6862
"lodash": "^4.17.11",
6963
"prop-types": "^15.7.2"
7064
},
7165
"peerDependencies": {
72-
"react": "^16.8.0"
66+
"react": "^16.3.0"
7367
},
7468
"devDependencies": {
7569
"@babel/cli": "^7.5.0",

src/firebaseConnect.js

+77-20
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import React from 'react'
1+
import React, { Component } from 'react'
22
import PropTypes from 'prop-types'
3+
import { isEqual, differenceWith } from 'lodash'
34
import hoistStatics from 'hoist-non-react-statics'
4-
import { invokeArrayQuery, wrapDisplayName } from './utils'
5-
import useFirebaseConnect from './useFirebaseConnect'
6-
import useFirebase from './useFirebase'
5+
import { watchEvents, unWatchEvents } from './actions/query'
6+
import { getEventsFromInput, createCallable, wrapDisplayName } from './utils'
7+
import ReactReduxFirebaseContext from './ReactReduxFirebaseContext'
78

89
/**
910
* Function that creates a Higher Order Component which
@@ -25,27 +26,83 @@ import useFirebase from './useFirebase'
2526
export const createFirebaseConnect = (storeKey = 'store') => (
2627
dataOrFn = []
2728
) => WrappedComponent => {
28-
const FirebaseConnect = function FirebaseConnect(props) {
29-
const contextFirebase = useFirebase()
30-
const firebase = props.firebase || contextFirebase
31-
const data = invokeArrayQuery(dataOrFn, props)
29+
class FirebaseConnectWrapped extends Component {
30+
static displayName = wrapDisplayName(
31+
WrappedComponent,
32+
'FirebaseConnectWrapped'
33+
)
34+
static wrappedComponent = WrappedComponent
3235

33-
useFirebaseConnect(data)
36+
firebaseEvents = []
37+
firebase = null
38+
prevData = null
3439

35-
return (
36-
<WrappedComponent
37-
firebase={firebase}
38-
dispatch={firebase.dispatch}
39-
{...props}
40-
/>
41-
)
40+
componentDidMount() {
41+
const { firebase, dispatch } = this.props
42+
43+
// Allow function to be passed
44+
const inputAsFunc = createCallable(dataOrFn)
45+
this.prevData = inputAsFunc(this.props, this.props)
46+
47+
const { ref, helpers, storage, database, auth } = firebase
48+
this.firebase = { ref, storage, database, auth, ...helpers }
49+
50+
this._firebaseEvents = getEventsFromInput(this.prevData)
51+
52+
watchEvents(firebase, dispatch, this._firebaseEvents)
53+
}
54+
55+
componentWillUnmount() {
56+
const { firebase, dispatch } = this.props
57+
unWatchEvents(firebase, dispatch, this._firebaseEvents)
58+
}
59+
60+
componentWillReceiveProps(np) {
61+
const { firebase, dispatch } = this.props
62+
const inputAsFunc = createCallable(dataOrFn)
63+
const data = inputAsFunc(np, this.store)
64+
// Handle a data parameter having changed
65+
if (!isEqual(data, this.prevData)) {
66+
const itemsToSubscribe = differenceWith(data, this.prevData, isEqual)
67+
const itemsToUnsubscribe = differenceWith(this.prevData, data, isEqual)
68+
69+
this.prevData = data
70+
// UnWatch all current events
71+
unWatchEvents(
72+
firebase,
73+
dispatch,
74+
getEventsFromInput(itemsToUnsubscribe)
75+
)
76+
// Get watch events from new data
77+
this._firebaseEvents = getEventsFromInput(data)
78+
79+
// Watch new events
80+
watchEvents(firebase, dispatch, getEventsFromInput(itemsToSubscribe))
81+
}
82+
}
83+
84+
render() {
85+
return <WrappedComponent {...this.props} />
86+
}
4287
}
4388

44-
hoistStatics(FirebaseConnect, WrappedComponent)
89+
FirebaseConnectWrapped.propTypes = {
90+
dispatch: PropTypes.func.isRequired,
91+
firebase: PropTypes.object.isRequired
92+
}
4593

46-
FirebaseConnect.propTypes = {
47-
...(WrappedComponent.propTypes || {}),
48-
firebase: PropTypes.object
94+
const FirebaseConnect = props => {
95+
return (
96+
<ReactReduxFirebaseContext.Consumer>
97+
{_internalFirebase => (
98+
<FirebaseConnectWrapped
99+
{...props}
100+
dispatch={_internalFirebase.dispatch}
101+
firebase={_internalFirebase}
102+
/>
103+
)}
104+
</ReactReduxFirebaseContext.Consumer>
105+
)
49106
}
50107

51108
FirebaseConnect.displayName = wrapDisplayName(

src/firestoreConnect.js

+81-27
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
import React from 'react'
1+
import React, { Component } from 'react'
22
import PropTypes from 'prop-types'
3+
import { isEqual, some, filter } from 'lodash'
34
import hoistStatics from 'hoist-non-react-statics'
4-
import { invokeArrayQuery, wrapDisplayName } from './utils'
5-
import useFirestoreConnect from './useFirestoreConnect'
6-
import useFirebase from './useFirebase'
7-
import useFirestore from './useFirestore'
5+
import { createCallable, wrapDisplayName } from './utils'
6+
import ReduxFirestoreContext from './ReduxFirestoreContext'
7+
import ReactReduxFirebaseContext from './ReactReduxFirebaseContext'
88

99
/**
1010
* Function that creates a Higher Order Component which
1111
* automatically listens/unListens to provided firebase paths using
12-
* React's Lifecycle hooks.
12+
* React's Lifecycle hooks. NOTE:
1313
* **WARNING!!** This is an advanced feature, and should only be used when
1414
* needing to access a firebase instance created under a different store key.
1515
* @param {String} [storeKey='store'] - Name of redux store which contains
@@ -26,37 +26,91 @@ import useFirestore from './useFirestore'
2626
export const createFirestoreConnect = (storeKey = 'store') => (
2727
dataOrFn = []
2828
) => WrappedComponent => {
29-
const FirestoreConnect = function FirestoreConnect(props) {
30-
const contextFirebase = useFirebase()
31-
const contextFirestore = useFirestore()
32-
const firebase = props.firebase || contextFirebase
33-
const firestore = props.firestore || contextFirestore
34-
const data = invokeArrayQuery(dataOrFn, props)
29+
class FirestoreConnectWrapped extends Component {
30+
static wrappedComponent = WrappedComponent
31+
static displayName = wrapDisplayName(
32+
WrappedComponent,
33+
'FirestoreConnectWrapped'
34+
)
3535

36-
useFirestoreConnect(data)
36+
prevData = null
3737

38-
return (
39-
<WrappedComponent
40-
firebase={firebase}
41-
firestore={firestore}
42-
dispatch={firebase.dispatch}
43-
{...props}
44-
/>
45-
)
38+
get firestoreIsEnabled() {
39+
return !!this.props.firestore
40+
}
41+
42+
componentDidMount() {
43+
if (this.firestoreIsEnabled) {
44+
// Listener configs as object (handling function being passed)
45+
const inputAsFunc = createCallable(dataOrFn)
46+
this.prevData = inputAsFunc(this.props, this.props)
47+
// Attach listeners based on listener config
48+
this.props.firestore.setListeners(this.prevData)
49+
}
50+
}
51+
52+
componentWillUnmount() {
53+
if (this.firestoreIsEnabled && this.prevData) {
54+
this.props.firestore.unsetListeners(this.prevData)
55+
}
56+
}
57+
58+
componentWillReceiveProps(np) {
59+
const { firestore } = this.props
60+
const inputAsFunc = createCallable(dataOrFn)
61+
const data = inputAsFunc(np, this.props)
62+
63+
// Check for changes in the listener configs
64+
if (this.firestoreIsEnabled && !isEqual(data, this.prevData)) {
65+
const changes = this.getChanges(data, this.prevData)
66+
67+
this.prevData = data
68+
69+
// Remove listeners for inactive subscriptions
70+
firestore.unsetListeners(changes.removed)
71+
// Add listeners for new subscriptions
72+
firestore.setListeners(changes.added)
73+
}
74+
}
75+
76+
getChanges(data = [], prevData = []) {
77+
const result = {}
78+
result.added = filter(data, d => !some(prevData, p => isEqual(d, p)))
79+
result.removed = filter(prevData, p => !some(data, d => isEqual(p, d)))
80+
return result
81+
}
82+
83+
render() {
84+
return <WrappedComponent {...this.props} />
85+
}
4686
}
4787

48-
FirestoreConnect.propTypes = {
88+
FirestoreConnectWrapped.propTypes = {
4989
dispatch: PropTypes.func,
5090
firebase: PropTypes.object,
5191
firestore: PropTypes.object
5292
}
5393

54-
FirestoreConnect.displayName = wrapDisplayName(
55-
WrappedComponent,
56-
'FirestoreConnect'
57-
)
94+
const HoistedComp = hoistStatics(FirestoreConnectWrapped, WrappedComponent)
5895

59-
FirestoreConnect.wrappedComponent = WrappedComponent
96+
const FirestoreConnect = props => {
97+
return (
98+
<ReactReduxFirebaseContext.Consumer>
99+
{firebase => (
100+
<ReduxFirestoreContext.Consumer>
101+
{firestore => (
102+
<HoistedComp
103+
{...props}
104+
dispatch={firebase.dispatch}
105+
firestore={firestore}
106+
firebase={firebase}
107+
/>
108+
)}
109+
</ReduxFirestoreContext.Consumer>
110+
)}
111+
</ReactReduxFirebaseContext.Consumer>
112+
)
113+
}
60114

61115
return hoistStatics(FirestoreConnect, WrappedComponent)
62116
}

0 commit comments

Comments
 (0)