Skip to content

Commit 80484d7

Browse files
authored
v3.0.0-beta
* feat(auth): remove `signIn` option from createUser (new user is automatically signed in through Firebase SDK) - #513 * feat(core): new pattern for getting extended firebase instance in thunks (added back `getFirebase` to api) - #635 * fix(HOCs): switch to `UNSAFE_componentWillReceiveProps` in class based HOCs to prevent warnings with 16.9.0 - #755 * fix(HOCs): switch `withFirebase` and `withFirestore` back to pre-hooks compatible logic * fix(core): replace lodash methods such as `isArray`, `isBoolean`, `isString`, `size`, `compact` and `isFunction` with native methods in a number of places * chore(deps): update lodash to 4.17.15 * chore(docs): add docs for how to reference data from state for reselect selectors - #614 * chore(docs): update client side role assign example in roles recipes - #699 * chore(docs): add example for assigning role in cloud function - #699
1 parent e8e93b8 commit 80484d7

34 files changed

+440
-267
lines changed

SUMMARY.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
* [Integrations](/docs/integrations/README.md)
2020
* [Redux Thunk](/docs/integrations/thunks.md)
2121
* [Redux Form](/docs/integrations/redux-form.md)
22+
* [Reselect](/docs/integrations/reselect.md)
2223
* [Redux Persist](/docs/integrations/redux-persist.md)
2324
* [Redux Saga](/docs/integrations/redux-saga.md)
2425
* [Redux Observable](/docs/integrations/redux-observable.md)
@@ -46,7 +47,7 @@
4647
* [dataReducer](/docs/api/reducers.md#datareducer)
4748
* [orderedReducer](/docs/api/reducers.md#orderedreducer)
4849
* [props.firebase](/docs/api/props-firebase.md)
49-
* [firebaseInstance](/docs/api/firebaseInstance.md)
50+
* [getFirebase](/docs/api/getFirebase.md)
5051
* [ReactReduxFirebaseContext](/docs/api/ReactReduxFirebaseContext.md)
5152
* [ReactReduxFirebaseProvider](/docs/api/ReactReduxFirebaseProvider.md)
5253
* [ReduxFirestoreContext](/docs/api/ReduxFirestoreContext.md)

docs/api/getFirebase.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# getFirebase
2+
3+
Expose Firebase instance created internally, which is the same as [props.firebase](/docs/api/props-firebase.md). Useful for
4+
integrations into external libraries such as redux-thunk and redux-observable.
5+
6+
The methods which are available are documented in [firebaseInstance](/docs/api/firebaseInstance.md)
7+
8+
**Examples**
9+
10+
_redux-thunk integration_
11+
12+
```javascript
13+
import { applyMiddleware, compose, createStore } from 'redux';
14+
import thunk from 'redux-thunk';
15+
import { getFirebase } from 'react-redux-firebase';
16+
import makeRootReducer from './reducers';
17+
18+
const store = createStore(
19+
makeRootReducer(),
20+
initialState,
21+
compose(
22+
applyMiddleware([
23+
// Pass getFirebase function as extra argument
24+
thunk.withExtraArgument(getFirebase)
25+
])
26+
)
27+
);
28+
29+
// then later
30+
export function addTodo(newTodo) {
31+
return (dispatch, getState, getFirebase) => {
32+
const firebase = getFirebase()
33+
firebase
34+
.push('todos', newTodo)
35+
.then(() => {
36+
dispatch({ type: 'SOME_ACTION' })
37+
})
38+
}
39+
}
40+
```

docs/api/helpers.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ Returns **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/
180180
181181
## populate
182182
183-
Populate with data from redux.
183+
Populate with data from multiple locations of redux state.
184184
185185
**Parameters**
186186

docs/auth.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,6 @@ Similar to Firebase's `ref.createUser(credentials)` but with support for automat
185185
* `credentials` [**Object**][object-url]
186186
* `credentials.email` [**String**][string-url] - User's email
187187
* `credentials.password` [**String**][string-url] - User's password
188-
* `credentials.signIn` [**String**][string-url] - Whether or not to sign in when user is signing up (defaults to `true`)
189188
190189
* `profile` [**Object**][object-url]
191190
* `profile.username` [**String**][string-url]

docs/integrations/reselect.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Reselect
2+
3+
There are a number of reasons to use state selectors, as mentioned in the [relesect docs](https://github.com/reduxjs/reselect):
4+
5+
> * Selectors can compute derived data, allowing Redux to store the minimal possible state.
6+
> * Selectors are efficient. A selector is not recomputed unless one of its arguments changes.
7+
> * Selectors are composable. They can be used as input to other selectors.
8+
9+
For more information, about why this is important, checkout the [motivation for memoized selectors sections of the reselect docs](https://github.com/reduxjs/reselect#motivation-for-memoized-selectors)
10+
11+
## State Selectors
12+
13+
Select only what you need from state in your selectors instead of the whole firebase/firestore state object:
14+
15+
```js
16+
import { createSelector } from 'reselect';
17+
import { connect } from 'react-redux'
18+
import { get, sumBy } from 'lodash'
19+
20+
const netTotalSelector = createSelector(
21+
state => get(state, 'firestore.data.products'),
22+
products => sumBy(products, 'price')
23+
)
24+
25+
connect((state) => ({
26+
netTotal: netTotalSelector(state)
27+
}))(Component)
28+
```
29+
30+
In this case Reselect will memoize the products object. That means that even if there's any update to other parts of redux state (including firebase/firestore), the memoized products object will stay the same until there is an update to the products themselves.
31+
32+
See [issue #614](https://github.com/prescottprue/react-redux-firebase/issues/614) for more info.

docs/integrations/thunks.md

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,81 @@
1-
# Thunks
1+
# redux-thunk Integration
22

3-
### redux-thunk integration
3+
## getFirebase As Extra Argument
44

55
In order to get the most out of writing your thunks, make sure to set up your thunk middleware using its redux-thunk's `withExtraArgument` method like so:
66

7+
**createStore.js**
8+
79
```javascript
810
import { applyMiddleware, compose, createStore } from 'redux';
911
import thunk from 'redux-thunk';
10-
import { reactReduxFirebase } from 'react-redux-firebase';
12+
import { getFirebase } from 'react-redux-firebase'
1113
import makeRootReducer from './reducers';
1214

1315
const fbConfig = {} // your firebase config
14-
16+
const middlewares = [
17+
thunk.withExtraArgument(getFirebase)
18+
]
1519
const store = createStore(
1620
makeRootReducer(),
1721
initialState,
1822
compose(
19-
applyMiddleware(thunk),
20-
reactReduxFirebase(fbConfig, { userProfile: 'users', enableLogging: false })
23+
applyMiddleware(...middlewares),
2124
)
2225
);
26+
```
27+
28+
**App.js**
29+
```js
30+
import React from 'react'
31+
import { Provider } from 'react-redux'
32+
import firebase from 'firebase/app'
33+
import 'firebase/auth'
34+
import 'firebase/database'
35+
import 'firebase/firestore' // make sure you add this for firestore
36+
import { ReactReduxFirebaseProvider } from 'react-redux-firebase';
37+
import { createFirestoreInstance } from 'redux-firestore';
38+
import Home from './Home'
39+
import createStore from './createStore'
40+
import { firebase as fbConfig, reduxFirebase as rfConfig } from './config'
41+
import './App.css'
2342

43+
// Initialize Firebase instance
44+
firebase.initializeApp(fbConfig)
45+
46+
const initialState = window && window.__INITIAL_STATE__ // set initial state here
47+
const store = createStore(initialState)
48+
49+
export default () => (
50+
<Provider store={store}>
51+
<ReactReduxFirebaseProvider
52+
firebase={firebase}
53+
config={rfConfig}
54+
dispatch={store.dispatch}
55+
createFirestoreInstance={createFirestoreInstance}>
56+
<Home />
57+
</ReactReduxFirebaseProvider>
58+
</Provider>
59+
)
2460
```
2561

2662
## Example Thunk
2763

2864
```javascript
29-
const sendNotification = (payload) => ({
30-
type: NOTIFICATION,
31-
payload
32-
})
33-
34-
export const addTodo = (newTodo) =>
35-
(dispatch, getState) => {
36-
return firebase
65+
function sendNotification(payload) {
66+
return {
67+
type: NOTIFICATION,
68+
payload
69+
}
70+
}
71+
72+
export function addTodo(newTodo) {
73+
return (dispatch, getState, getFirebase) => {
74+
return getFirebase()
3775
.ref('todos')
3876
.push(newTodo)
3977
.then(() => {
4078
dispatch(sendNotification('Todo Added'))
4179
})
42-
};
43-
80+
}
4481
```

docs/recipes/auth.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,8 @@ import StyledFirebaseAuth from 'react-firebaseui/StyledFirebaseAuth';
6060
// import { withRouter } from 'react-router-dom'; // if you use react-router
6161
// import GoogleButton from 'react-google-button' // optional
6262

63-
export const LoginPage = ({
64-
firebase,
65-
auth,
66-
//history if you use react-router
67-
}) => (
63+
function LoginPage({ firebase, auth }) {
64+
return (
6865
<div className={classes.container}>
6966
<StyledFirebaseAuth
7067
uiConfig={{

docs/recipes/roles.md

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ reactReduxFirebase(
8282

8383
## Automatically assign role when user signs up
8484

85-
If you want to assign a role by default when users sign up, you can add a profileFactory to your config:+
85+
### Client Side
86+
87+
If you want to assign a role by default when users sign up, you can add a profileFactory to your config:
8688

8789
```js
8890
reactReduxFirebase(
@@ -92,15 +94,39 @@ reactReduxFirebase(
9294
profileParamsToPopulate: [
9395
{ child: 'role', root: 'roles' }, // populates user's role with matching role object from roles
9496
],
95-
profileFactory: user => ({
96-
email: user.email || user.providerData[0].email,
97-
role: 'user',
98-
providerData: user.providerData
99-
})
97+
profileFactory: user => {
98+
const profile = {
99+
email: user.email || user.providerData[0].email,
100+
role: 'user',
101+
}
102+
if (user.providerData && user.providerData.length) {
103+
profile.providerData = user.providerData
104+
}
105+
}
100106
}
101107
)
102108
```
103109

110+
**NOTE**: Your security rules should be set to only allow for users to be setting their role to user. For more granular control of this, you can move role assigning to a cloud function that is trigger on user create
111+
112+
### Cloud Function
113+
114+
Having cloud function contain logic about which users get assigned certain roles means that you do not need any write access for clients on the role parameter.
115+
116+
```js
117+
const adminEmails = ['[email protected]'] // list of emails to automatically assign admin role to
118+
119+
async function assignUserRole(user) {
120+
const { uid, email, displayName } = user; // The email of the user.
121+
const newRole = adminEmails.includes(email) ? 'admin' : 'user'
122+
await admin.firestore().collection('users').doc(uid).set({ role: 'user' }, { merge: true })
123+
}
124+
125+
exports.assignUserRole = functions.auth.user().onCreate(assignUserRole);
126+
```
127+
128+
More info is available about doing this in the [extend auth with functions section of the firebase docs](https://firebase.google.com/docs/auth/extend-with-functions).
129+
104130
## The higher order component (where the actual verification happens)
105131

106132
Using redux-auth-wrapper you can create higher order components that will make it easy to verify a user has a specific role or permission before rendering a page or component.

docs/v3-migration-guide.md

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,22 @@
22

33
## What Changed
44

5+
### Features
6+
57
* Support `react-redux` v6 and new React Context API - [#581](https://github.com/prescottprue/react-redux-firebase/issues/581). This mean no more `reactReduxFirebase` and `reduxFirestore` store enhancers (instance is passed through the new React context API) - [#581](https://github.com/prescottprue/react-redux-firebase/issues/581)
8+
* React hooks (requires react `^16.8.0`) `useFirebase`, `useFirestore`, `useFirestoreConnect`, and `useFirebaseConnect` - (Tons of work by [@illuminist](https://github.com/illuminist))
9+
10+
### Breaking Changes
11+
12+
* Removed from API:
13+
* `reactReduxFirebase` store enhancer (firebase instance is now created by context providers)
14+
* `createFirebaseConnect` and `createFirestoreConnect` (see [below](#remove-createFirebaseConnect-and-createFirestoreConnect))
15+
* `signIn` option from `createUser` (new user is automatically signed in through Firebase SDK) - #513
616
* `componentDidMount` used in place of `componentWillMount` for data loading in `firebaseConnect` and `firestoreConnect`
7-
* `getFirebase` no longer part of the API
8-
* `createFirebaseConnect` and `createFirestoreConnect` are no longer part of the API
917

10-
### Remove createFirebaseConnect and createFirestoreConnect
18+
### Change Snippets
19+
20+
#### Remove createFirebaseConnect and createFirestoreConnect
1121

1222
These are no longer needed since the extended firebase instance is now loaded through react context instead of through `store.firebase`.
1323

@@ -16,23 +26,23 @@ These are no longer needed since the extended firebase instance is now loaded th
1626
- const firestoreConnect = createFirestoreConnect('otherStoreKey')
1727
```
1828

19-
### Remove Store Enhancer
29+
#### Remove Store Enhancer
2030

2131
Replace store enhancer with `ReactReduxFirebaseProvider`
2232

23-
#### Diff
33+
##### Diff
2434

2535
_RTDB Diff_
2636
```diff
27-
+ import { ReactReduxFirebaseProvider } from 'react-redux-firebase'
37+
+ import { ReactReduxFirebaseProvider, getFirebase } from 'react-redux-firebase'
2838
- import { reactReduxFirebase, getFirebase } from 'react-redux-firebase'
2939

3040
const store = createStore(
3141
rootReducer,
3242
initialState,
3343
- compose(
3444
- reactReduxFirebase(firebase, rrfConfig), // pass in firebase instance instead of config
35-
- applyMiddleware([ thunk.withExtraArgument(getFirebase) ]) // to add other middleware
45+
applyMiddleware([ thunk.withExtraArgument(getFirebase) ]) // to add other middleware
3646
- )
3747
)
3848

@@ -82,7 +92,7 @@ const App = () => (
8292
);
8393
```
8494

85-
#### Full Examples
95+
## Code Examples
8696

8797
**`v2.*.*`**
8898

examples/complete/simple/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
"react-redux-firebase": "next",
1717
"recompose": "^0.30.0",
1818
"redux": "^4.0.4",
19-
"redux-firestore": "^0.8.0"
19+
"redux-firestore": "^0.8.0",
20+
"redux-thunk": "^2.3.0"
2021
},
2122
"devDependencies": {
2223
"react-scripts": "3.1.0"

0 commit comments

Comments
 (0)