1
- import React from 'react'
1
+ import React , { Component } from 'react'
2
2
import PropTypes from 'prop-types'
3
+ import { isEqual , some , filter } from 'lodash'
3
4
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'
8
8
9
9
/**
10
10
* Function that creates a Higher Order Component which
11
11
* automatically listens/unListens to provided firebase paths using
12
- * React's Lifecycle hooks.
12
+ * React's Lifecycle hooks. NOTE:
13
13
* **WARNING!!** This is an advanced feature, and should only be used when
14
14
* needing to access a firebase instance created under a different store key.
15
15
* @param {String } [storeKey='store'] - Name of redux store which contains
@@ -26,37 +26,91 @@ import useFirestore from './useFirestore'
26
26
export const createFirestoreConnect = ( storeKey = 'store' ) => (
27
27
dataOrFn = [ ]
28
28
) => 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
+ )
35
35
36
- useFirestoreConnect ( data )
36
+ prevData = null
37
37
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
+ }
46
86
}
47
87
48
- FirestoreConnect . propTypes = {
88
+ FirestoreConnectWrapped . propTypes = {
49
89
dispatch : PropTypes . func ,
50
90
firebase : PropTypes . object ,
51
91
firestore : PropTypes . object
52
92
}
53
93
54
- FirestoreConnect . displayName = wrapDisplayName (
55
- WrappedComponent ,
56
- 'FirestoreConnect'
57
- )
94
+ const HoistedComp = hoistStatics ( FirestoreConnectWrapped , WrappedComponent )
58
95
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
+ }
60
114
61
115
return hoistStatics ( FirestoreConnect , WrappedComponent )
62
116
}
0 commit comments