Skip to content

Commit e46009a

Browse files
authored
v3.0.0-beta.3
* feat(types): add back type for `getFirebase` - #763 * feat(storage): pass file metadata through `uploadFile` to `storage.put` calls - #720 * feat(examples): update material and simple examples * feat(docs): update docs with new hooks API
1 parent 60b5e86 commit e46009a

File tree

95 files changed

+3769
-3168
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+3769
-3168
lines changed

.eslintrc.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,17 @@
11
module.exports = {
22
root: true,
3-
43
parser: 'babel-eslint',
5-
64
extends: ['standard', 'standard-react', 'prettier', 'prettier/react'],
7-
plugins: ['babel', 'react', 'prettier'],
8-
5+
plugins: ['babel', 'react', 'prettier', 'react-hooks'],
96
settings: {
107
react: {
118
version: 'detect'
129
}
1310
},
14-
1511
env: {
1612
browser: true,
1713
es6: true
1814
},
19-
2015
rules: {
2116
semi: [2, 'never'],
2217
'no-console': 'error',

README.md

Lines changed: 50 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,7 @@ import 'firebase/auth'
5656
// import 'firebase/firestore' // <- needed if using firestore
5757
// import 'firebase/functions' // <- needed if using httpsCallable
5858
import { createStore, combineReducers, compose } from 'redux'
59-
import ReactReduxFirebaseProvider from 'react-redux-firebase/lib/ReactReduxFirebaseProvider'
60-
import firebaseReducer from 'react-redux-firebase/lib/reducer'
59+
import { ReactReduxFirebaseProvider, firebaseReducer } from 'react-redux-firebase'
6160
// import { createFirestoreInstance, firestoreReducer } from 'redux-firestore' // <- needed if using firestore
6261

6362
const fbConfig = {}
@@ -112,11 +111,16 @@ The Firebase instance can then be grabbed from context within your components (`
112111

113112
```jsx
114113
import React from 'react'
115-
import PropTypes from 'prop-types'
116-
import withFirebase from 'react-redux-firebase/lib/withFirebase'
117-
import { compose, withHandlers } from 'recompose'
114+
import { useFirebase } from 'react-redux-firebase'
115+
116+
export default function Todos() {
117+
const firebase = useFirebase()
118+
119+
function addSampleTodo() {
120+
const sampleTodo = { text: 'Sample', done: false }
121+
return firebase.push('todos', sampleTodo)
122+
}
118123

119-
function Todos({ firebase, addSampleTodo }) {
120124
return (
121125
<div>
122126
<h1>New Sample Todo</h1>
@@ -126,37 +130,31 @@ function Todos({ firebase, addSampleTodo }) {
126130
</div>
127131
)
128132
}
129-
130-
const enhance = compose(
131-
withFirebase,
132-
withHandlers({
133-
addSampleTodo: props => () => {
134-
const sampleTodo = { text: 'Sample', done: false }
135-
return props.firebase.push('todos', sampleTodo)
136-
}
137-
})
138-
)
139-
140-
export default enhance(Todos)
141133
```
142134

143135
**Load Data (listeners automatically managed on mount/unmount)**
144136

145137
```jsx
146138
import React from 'react'
147139
import PropTypes from 'prop-types'
148-
import { connect } from 'react-redux'
149-
import { compose } from 'redux'
150-
import firebaseConnect from 'react-redux-firebase/lib/firebaseConnect'
151-
import { isLoaded, isEmpty } from 'react-redux-firebase/lib/helpers'
140+
import { useSelector } from 'react-redux'
141+
import { useFirebaseConnect, isLoaded, isEmpty } from 'react-redux-firebase'
142+
143+
export default function Todos() {
144+
useFirebaseConnect([
145+
'todos' // { path: '/todos' } // object notation
146+
])
147+
148+
const todos = useSelector(state => state.firebase.ordered.todos)
152149

153-
function Todos({ todos, firebase }) {
154150
if (!isLoaded(todos)) {
155151
return <div>Loading...</div>
156152
}
153+
157154
if (isEmpty(todos)) {
158155
return <div>Todos List Is Empty</div>
159156
}
157+
160158
return (
161159
<div>
162160
<ul>
@@ -171,50 +169,34 @@ function Todos({ todos, firebase }) {
171169
</div>
172170
)
173171
}
174-
175-
export default compose(
176-
firebaseConnect(() => [
177-
'todos' // { path: '/todos' } // object notation
178-
]),
179-
connect(state => ({
180-
todos: state.firebase.data.todos
181-
// profile: state.firebase.profile // load profile
182-
}))
183-
)(Todos)
184172
```
185173

186-
**Queries Based On Props**
174+
**Queries Based On Route Params**
187175

188176
It is common to make a detail page that loads a single item instead of a whole list of items. A query for a specific `Todos` can be created using
189177

190178
```jsx
191179
import React from 'react'
192180
import PropTypes from 'prop-types'
193-
import { connect } from 'react-redux'
194181
import { get } from 'lodash'
195-
import firebaseConnect from 'react-redux-firebase/lib/firebaseConnect'
196-
import { compose, withHandlers } from 'recompose'
197-
198-
// Component enhancer that loads todo into redux then into the todo prop
199-
const enhance = compose(
200-
firebaseConnect(props => {
201-
// Set listeners based on props (prop is route parameter from react-router in this case)
202-
return [
203-
{ path: `todos/${props.params.todoId}` } // create todo listener
204-
// `todos/${props.params.todoId}` // equivalent string notation
205-
]
206-
}),
207-
connect(({ firebase }, props) => ({
208-
todo: getVal(firebase, `data/todos/${props.params.todoId}`), // lodash's get can also be used
209-
})),
210-
withHandlers({
211-
updateTodo: props => () => {
212-
return firebase.update(`todos/${params.todoId}`, { done: !todo.isDone })
213-
}
214-
})
215-
)
216-
217-
function Todo({ todo }) {
182+
import { useSelector } from 'react-redux'
183+
import { useFirebaseConnect } from 'react-redux-firebase'
184+
import { useParams } from 'react-router-dom'
185+
186+
export default function Todo() {
187+
const { todoId } = useParams() // matches todos/:todoId in route
188+
189+
useFirebaseConnect([
190+
{ path: `todos/${todoId}` } // create todo listener
191+
// `todos/${props.params.todoId}` // equivalent string notation
192+
])
193+
194+
const todo = useSelector(({ firebase: { data } }) => data.todos && data.todos[todoId])
195+
196+
function updateTodo() {
197+
return firebase.update(`todos/${params.todoId}`, { done: !todo.isDone })
198+
}
199+
218200
return (
219201
<div>
220202
<input
@@ -227,27 +209,26 @@ function Todo({ todo }) {
227209
</div>
228210
)
229211
}
230-
231-
// Export enhanced component
232-
export default enhance(Todo)
233212
```
234213

235214
**Load Data On Click**
236215

237216
```jsx
238217
import React from 'react'
239-
import PropTypes from 'prop-types'
240-
import { connect } from 'react-redux'
241-
import { compose } from 'redux'
242-
import { withFirebase, isLoaded, isEmpty } from 'react-redux-firebase'
218+
import { useSelector } from 'react-redux'
219+
import { useFirebase, isLoaded, isEmpty } from 'react-redux-firebase'
220+
221+
function TodosList() {
222+
const todos = useSelector(state => state.firebase.ordered.todos)
243223

244-
function TodosList({ todos }) {
245224
if (!isLoaded(todos)) {
246225
return <div>Loading...</div>
247226
}
227+
248228
if (isEmpty(todos)) {
249229
return <div>Todos List Is Empty</div>
250230
}
231+
251232
return (
252233
<ul>
253234
{
@@ -258,17 +239,10 @@ function TodosList({ todos }) {
258239
</ul>
259240
)
260241
}
261-
const withTodosData = compose(
262-
withFirebase, // or firebaseConnect()
263-
connect((state) => ({
264-
todos: state.firebase.data.todos,
265-
// profile: state.firebase.profile // load profile
266-
}))
267-
)
268242

269-
const EnhancedTodosList = withTodosData(TodosList)
243+
function Todos() {
244+
const firebase = useFirebase()
270245

271-
function Todos({ firebase }) {
272246
return (
273247
<div>
274248
<h1>Todos</h1>
@@ -281,7 +255,7 @@ function Todos({ firebase }) {
281255
}
282256

283257
// Export enhanced component
284-
export default withFirebase(Todos)
258+
export default Todos
285259
```
286260

287261
## Firestore

SUMMARY.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,15 @@
2727
* [React Chrome Redux](/docs/integrations/react-chrome-redux.md)
2828
* [API Reference](/docs/api/README.md)
2929
* [constants](/docs/api/constants.md)
30-
* [firebaseConnect](/docs/api/firebaseConnect.md)
31-
* [withFirebase](/docs/api/withFirebase.md)
32-
* [firestoreConnect](/docs/api/firestoreConnect.md)
33-
* [withFirestore](/docs/api/withFirestore.md)
34-
* [useFirebase](/docs/api/useFirebase.md)
35-
* [useFirebaseConnect](/docs/api/useFirebaseConnect.md)
36-
* [useFirestore](/docs/api/useFirestore.md)
30+
* Hooks
31+
* [useFirebase](/docs/api/useFirebase.md)
32+
* [useFirebaseConnect](/docs/api/useFirebaseConnect.md)
33+
* [useFirestore](/docs/api/useFirestore.md)
34+
* HOCs
35+
* [firebaseConnect](/docs/api/firebaseConnect.md)
36+
* [withFirebase](/docs/api/withFirebase.md)
37+
* [firestoreConnect](/docs/api/firestoreConnect.md)
38+
* [withFirestore](/docs/api/withFirestore.md)
3739
* [firebaseReducer](/docs/api/reducer.md)
3840
* [isInitializingReducer](/docs/api/reducers.md#isinitializingreducer)
3941
* [requestingReducer](/docs/api/reducers.md#requestingreducer)

docs/auth.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -296,18 +296,18 @@ const recaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button',
296296
'size': 'invisible',
297297
});
298298
firebase.signInWithPhoneNumber(phoneNumber, appVerifier)
299-
.then((confirmationResult) => {
300-
// SMS sent. Prompt user to type the code from the message, then sign the
301-
// user in with confirmationResult.confirm(code).
302-
const verificationCode = window.prompt('Please enter the verification ' +
303-
'code that was sent to your mobile device.');
304-
return confirmationResult.confirm(verificationCode);
305-
})
306-
.catch((error) => {
307-
// Error; SMS not sent
308-
// Handle Errors Here
309-
return Promise.reject(error)
310-
});
299+
.then((confirmationResult) => {
300+
// SMS sent. Prompt user to type the code from the message, then sign the
301+
// user in with confirmationResult.confirm(code).
302+
const verificationCode = window.prompt('Please enter the verification ' +
303+
'code that was sent to your mobile device.');
304+
return confirmationResult.confirm(verificationCode);
305+
})
306+
.catch((error) => {
307+
// Error; SMS not sent
308+
// Handle Errors Here
309+
return Promise.reject(error)
310+
});
311311
```
312312
313313
##### Parameters

docs/firestore.md

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,15 @@ const rrfProps = {
5555
}
5656

5757
// Setup react-redux so that connect HOC can be used
58-
const App = () => (
59-
<Provider store={store}>
60-
<ReactReduxFirebaseProvider {...rrfProps}>
61-
<Todos />
62-
</ReactReduxFirebaseProvider>
63-
</Provider>
64-
);
58+
function App() {
59+
return (
60+
<Provider store={store}>
61+
<ReactReduxFirebaseProvider {...rrfProps}>
62+
<Todos />
63+
</ReactReduxFirebaseProvider>
64+
</Provider>
65+
);
66+
}
6567

6668
render(<App/>, document.getElementById('root'));
6769
```
@@ -83,10 +85,46 @@ const rrfConfig = {
8385

8486
Firestore queries can be created in two ways:
8587

86-
* [Automatically](#firestoreConnect) - Using `firestoreConnect` HOC (manages mounting/unmounting)
88+
* [Automatically with Hook](#useFirestoreConnect) - Using `useFirestoreConnect` hook (manages mounting/unmounting)
89+
* [Automatically with HOC](#firestoreConnect) - Using `firestoreConnect` HOC (manages mounting/unmounting)
8790
* [Manually](#manual) - Using `get`, or by setting listeners with `setListeners`/`setListener` (requires managing of listeners)
8891

89-
### Automatic {#firestoreConnect}
92+
### Automatically with Hook {#useFirestoreConnect}
93+
94+
`useFirestoreConnect` is a React hook that manages attaching and detaching listeners for you as the component mounts and unmounts.
95+
96+
#### Examples
97+
1. Basic query that will attach/detach as the component passed mounts/unmounts. In this case we are setting a listener for the `'todos'` collection:
98+
99+
```js
100+
import React from 'react'
101+
import { useSelector } from 'react-redux'
102+
import { useFirestoreConnect } from 'react-redux-firebase'
103+
104+
export default function SomeComponent() {
105+
useFirestoreConnect([
106+
{ collection: 'todos' } // or 'todos'
107+
])
108+
const todos = useSelector(state => state.firestore.ordered.todos)
109+
}
110+
```
111+
112+
2. Props can be used as part of queries. In this case we will get a specific todo:
113+
114+
```js
115+
import React from 'react'
116+
import { useSelector } from 'react-redux'
117+
import { useFirestoreConnect } from 'react-redux-firebase'
118+
119+
export default function SomeComponent({ todoId }) {
120+
useFirestoreConnect(() => [
121+
{ collection: 'todos', doc: todoId } // or `todos/${props.todoId}`
122+
])
123+
const todos = useSelector(({ firestore: { ordered } }) => ordered.todos && ordered.todos[todoId])
124+
}
125+
```
126+
127+
### Automatically with HOC {#firestoreConnect}
90128

91129
`firestoreConnect` is a React Higher Order component that manages attaching and detaching listeners for you as the component mounts and unmounts. It is possible to roll a similar solution yourself, but can get complex when dealing with advanced situations (queries based on props, props changing, etc.)
92130

docs/getting_started.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,15 @@ const rrfProps = {
7373
}
7474

7575
// Setup react-redux so that connect HOC can be used
76-
const App = () => (
77-
<Provider store={store}>
78-
<ReactReduxFirebaseProvider {...rrfProps}>
79-
<Todos />
80-
</ReactReduxFirebaseProvider>
81-
</Provider>
82-
);
76+
function App() {
77+
return (
78+
<Provider store={store}>
79+
<ReactReduxFirebaseProvider {...rrfProps}>
80+
<Todos />
81+
</ReactReduxFirebaseProvider>
82+
</Provider>
83+
);
84+
}
8385

8486
render(<App/>, document.getElementById('root'));
8587
```

0 commit comments

Comments
 (0)