1 | # redux-firestore
|
2 |
|
3 | [![NPM version][npm-image]][npm-url]
|
4 | [![NPM downloads][npm-downloads-image]][npm-url]
|
5 | [![License][license-image]][license-url]
|
6 | [![Code Style][code-style-image]][code-style-url]
|
7 | [![Dependency Status][daviddm-image]][daviddm-url]
|
8 | [![Build Status][travis-image]][travis-url]
|
9 | [![Code Coverage][coverage-image]][coverage-url]
|
10 |
|
11 | [![Gitter][gitter-image]][gitter-url]
|
12 |
|
13 |
|
14 | > Redux bindings for Firestore. Provides low-level API used in other libraries such as [react-redux-firebase](https://github.com/prescottprue/react-redux-firebase)
|
15 |
|
16 | ## Installation
|
17 |
|
18 | ```sh
|
19 | npm install redux-firestore --save
|
20 | ```
|
21 |
|
22 | This assumes you are using [npm](https://www.npmjs.com/) as your package manager.
|
23 |
|
24 | If you're not, you can access the library on [unpkg](https://unpkg.com/redux-firestore@latest/dist/redux-firestore.min.js), download it, or point your package manager to it. Theres more on this in the [Builds section below](#builds)
|
25 |
|
26 | ## Complementary Package
|
27 |
|
28 | Most likely, you'll want react bindings, for that you will need [react-redux-firebase](https://github.com/prescottprue/react-redux-firebase). You can install the current version it by running:
|
29 |
|
30 | ```sh
|
31 | npm install --save react-redux-firebase
|
32 | ```
|
33 |
|
34 | [react-redux-firebase](https://github.com/prescottprue/react-redux-firebase) provides [`withFirestore`](http://react-redux-firebase.com/docs/api/withFirestore.html) and [`firestoreConnect`](http://react-redux-firebase.com/docs/api/firestoreConnect.html) higher order components, which handle automatically calling `redux-firestore` internally based on component's lifecycle (i.e. mounting/un-mounting)
|
35 |
|
36 | ## Use
|
37 |
|
38 | ```javascript
|
39 | import { createStore, combineReducers, compose } from 'redux'
|
40 | import { reduxFirestore, firestoreReducer } from 'redux-firestore'
|
41 | import firebase from 'firebase/app'
|
42 | import 'firebase/auth'
|
43 | import 'firebase/database'
|
44 | import 'firebase/firestore'
|
45 |
|
46 | const firebaseConfig = {} // from Firebase Console
|
47 | const rfConfig = {} // optional redux-firestore Config Options
|
48 |
|
49 | // Initialize firebase instance
|
50 | firebase.initializeApp(firebaseConfig)
|
51 | // Initialize Cloud Firestore through Firebase
|
52 | firebase.firestore();
|
53 |
|
54 | // Add reduxFirestore store enhancer to store creator
|
55 | const createStoreWithFirebase = compose(
|
56 | reduxFirestore(firebase, rfConfig), // firebase instance as first argument, rfConfig as optional second
|
57 | )(createStore)
|
58 |
|
59 | // Add Firebase to reducers
|
60 | const rootReducer = combineReducers({
|
61 | firestore: firestoreReducer
|
62 | })
|
63 |
|
64 | // Create store with reducers and initial state
|
65 | const initialState = {}
|
66 | const store = createStoreWithFirebase(rootReducer, initialState)
|
67 | ```
|
68 |
|
69 | Then pass store to your component's context using [react-redux's `Provider`](https://github.com/reactjs/react-redux/blob/master/docs/api.md#provider-store):
|
70 |
|
71 | ```js
|
72 | import React from 'react';
|
73 | import { render } from 'react-dom';
|
74 | import { Provider } from 'react-redux';
|
75 |
|
76 | render(
|
77 | <Provider store={store}>
|
78 | <MyRootComponent />
|
79 | </Provider>,
|
80 | rootEl
|
81 | )
|
82 | ```
|
83 |
|
84 | ### Call Firestore
|
85 |
|
86 | #### Firestore Instance
|
87 |
|
88 | ##### Functional Components
|
89 |
|
90 | It is common to make react components "functional" meaning that the component is just a function instead of being a `class` which `extends React.Component`. This can be useful, but can limit usage of lifecycle hooks and other features of Component Classes. [`recompose` helps solve this](https://github.com/acdlite/recompose/blob/master/docs/API.md) by providing Higher Order Component functions such as `withContext`, `lifecycle`, and `withHandlers`.
|
91 |
|
92 | ```js
|
93 | import { connect } from 'react-redux'
|
94 | import {
|
95 | compose,
|
96 | withHandlers,
|
97 | lifecycle,
|
98 | withContext,
|
99 | getContext
|
100 | } from 'recompose'
|
101 |
|
102 | const withStore = compose(
|
103 | withContext({ store: PropTypes.object }, () => {}),
|
104 | getContext({ store: PropTypes.object }),
|
105 | )
|
106 |
|
107 | const enhance = compose(
|
108 | withStore,
|
109 | withHandlers({
|
110 | loadData: props => () => props.store.firestore.get('todos'),
|
111 | onDoneClick: props => (key, done = false) =>
|
112 | props.store.firestore.update(`todos/${key}`, { done }),
|
113 | onNewSubmit: props => newTodo =>
|
114 | props.store.firestore.add('todos', { ...newTodo, owner: 'Anonymous' }),
|
115 | }),
|
116 | lifecycle({
|
117 | componentDidMount(props) {
|
118 | props.loadData()
|
119 | }
|
120 | }),
|
121 | connect(({ firebase }) => ({ // state.firebase
|
122 | todos: firebase.ordered.todos,
|
123 | }))
|
124 | )
|
125 |
|
126 | export default enhance(SomeComponent)
|
127 | ```
|
128 |
|
129 | For more information [on using recompose visit the docs](https://github.com/acdlite/recompose/blob/master/docs/API.md)
|
130 |
|
131 | ##### Component Class
|
132 |
|
133 | ```js
|
134 | import React, { Component } from 'react'
|
135 | import PropTypes from 'prop-types'
|
136 | import { connect } from 'react-redux'
|
137 | import { watchEvents, unWatchEvents } from './actions/query'
|
138 | import { getEventsFromInput, createCallable } from './utils'
|
139 |
|
140 | class Todos extends Component {
|
141 | static contextTypes = {
|
142 | store: PropTypes.object.isRequired
|
143 | }
|
144 |
|
145 | componentDidMount () {
|
146 | const { firestore } = this.context.store
|
147 | firestore.get('todos')
|
148 | }
|
149 |
|
150 | render () {
|
151 | return (
|
152 | <div>
|
153 | {
|
154 | todos.map(todo => (
|
155 | <div key={todo.id}>
|
156 | {JSON.stringify(todo)}
|
157 | </div>
|
158 | ))
|
159 | }
|
160 | </div>
|
161 | )
|
162 | }
|
163 | }
|
164 |
|
165 | export default connect((state) => ({
|
166 | todos: state.firestore.ordered.todos
|
167 | }))(Todos)
|
168 | ```
|
169 | ### API
|
170 | The `store.firestore` instance created by the `reduxFirestore` enhancer extends [Firebase's JS API for Firestore](https://firebase.google.com/docs/reference/js/firebase.firestore). This means all of the methods regularly available through `firebase.firestore()` and the statics available from `firebase.firestore` are available. Certain methods (such as `get`, `set`, and `onSnapshot`) have a different API since they have been extended with action dispatching. The methods which have dispatch actions are listed below:
|
171 |
|
172 | #### Actions
|
173 |
|
174 | ##### get
|
175 | ```js
|
176 | store.firestore.get({ collection: 'cities' }),
|
177 | // store.firestore.get({ collection: 'cities', doc: 'SF' }), // doc
|
178 | ```
|
179 |
|
180 | ##### set
|
181 | ```js
|
182 | store.firestore.set({ collection: 'cities', doc: 'SF' }, { name: 'San Francisco' }),
|
183 | ```
|
184 |
|
185 | ##### add
|
186 | ```js
|
187 | store.firestore.add({ collection: 'cities' }, { name: 'Some Place' }),
|
188 | ```
|
189 |
|
190 | ##### update
|
191 | ```js
|
192 | const itemUpdates = {
|
193 | some: 'value',
|
194 | updatedAt: store.firestore.FieldValue.serverTimestamp()
|
195 | }
|
196 |
|
197 | store.firestore.update({ collection: 'cities', doc: 'SF' }, itemUpdates),
|
198 | ```
|
199 |
|
200 | ##### delete
|
201 | ```js
|
202 | store.firestore.delete({ collection: 'cities', doc: 'SF' }),
|
203 | ```
|
204 |
|
205 | ##### runTransaction
|
206 | ```js
|
207 | store.firestore.runTransaction(t => {
|
208 | return t.get(cityRef)
|
209 | .then(doc => {
|
210 | // Add one person to the city population
|
211 | const newPopulation = doc.data().population + 1;
|
212 | t.update(cityRef, { population: newPopulation });
|
213 | });
|
214 | })
|
215 | .then(result => {
|
216 | // TRANSACTION_SUCCESS action dispatched
|
217 | console.log('Transaction success!');
|
218 | }).catch(err => {
|
219 | // TRANSACTION_FAILURE action dispatched
|
220 | console.log('Transaction failure:', err);
|
221 | });
|
222 | ```
|
223 |
|
224 | #### Types of Queries
|
225 | Each of these functions take a queryOptions object with options as described in the [Query Options section of this README](#query-options). Some simple query options examples are used here for better comprehension.
|
226 | ##### get
|
227 | ```js
|
228 | props.store.firestore.get({ collection: 'cities' }),
|
229 | // store.firestore.get({ collection: 'cities', doc: 'SF' }), // doc
|
230 | ```
|
231 |
|
232 | ##### onSnapshot/setListener
|
233 |
|
234 | ```js
|
235 | store.firestore.onSnapshot({ collection: 'cities' }),
|
236 | // store.firestore.setListener({ collection: 'cities' }), // alias
|
237 | // store.firestore.setListener({ collection: 'cities', doc: 'SF' }), // doc
|
238 | ```
|
239 |
|
240 | ##### setListeners
|
241 |
|
242 | ```js
|
243 | store.firestore.setListeners([
|
244 | { collection: 'cities' },
|
245 | { collection: 'users' },
|
246 | ]),
|
247 | ```
|
248 |
|
249 | ##### unsetListener / unsetListeners
|
250 | After setting a listener/multiple listeners, you can unset them with the following two functions. In order to unset a specific listener, you must pass the same queryOptions object given to onSnapshot/setListener(s).
|
251 | ```js
|
252 | store.firestore.unsetListener({ collection: 'cities' }),
|
253 | // of for any number of listeners at once :
|
254 | store.firestore.unsetListeners([query1Options, query2Options]),
|
255 | // here query1Options as in { collection: 'cities' } for example
|
256 | ```
|
257 |
|
258 | #### Query Options
|
259 |
|
260 | ##### Collection
|
261 | ```js
|
262 | { collection: 'cities' },
|
263 | // or string equivalent
|
264 | // store.firestore.get('cities'),
|
265 | ```
|
266 |
|
267 | ##### Document
|
268 |
|
269 | ```js
|
270 | { collection: 'cities', doc: 'SF' },
|
271 | // or string equivalent
|
272 | // props.store.firestore.get('cities/SF'),
|
273 | ```
|
274 |
|
275 | ##### Sub Collections
|
276 |
|
277 | ```js
|
278 | { collection: 'cities', doc: 'SF', subcollections: [{ collection: 'zipcodes' }] },
|
279 | // or string equivalent
|
280 | // props.store.firestore.get('cities/SF'/zipcodes),
|
281 | ```
|
282 |
|
283 | **Note:** When nesting sub-collections, [`storeAs`](#storeas) should be used for more optimal state updates.
|
284 |
|
285 | ##### Where
|
286 |
|
287 | To create a single `where` call, pass a single argument array to the `where` parameter:
|
288 |
|
289 | ```js
|
290 | {
|
291 | collection: 'cities',
|
292 | where: ['state', '==', 'CA']
|
293 | },
|
294 | ```
|
295 |
|
296 | Multiple `where` queries are as simple as passing multiple argument arrays (each one representing a `where` call):
|
297 |
|
298 | ```js
|
299 | {
|
300 | collection: 'cities',
|
301 | where: [
|
302 | ['state', '==', 'CA'],
|
303 | ['population', '<', 100000]
|
304 | ]
|
305 | },
|
306 | ```
|
307 |
|
308 | Firestore doesn't alow you to create `or` style queries. Instead, you should pass in multiple queries and compose your data.
|
309 |
|
310 | ``` javascript
|
311 | ['sally', 'john', 'peter'].map(friendId => ({
|
312 | collection: 'users',
|
313 | where: [
|
314 | ['id', '==', friendId],
|
315 | ['isOnline', '==', true]
|
316 | ]
|
317 | storeAs: 'onlineFriends'
|
318 | }));
|
319 | ```
|
320 |
|
321 | Since the results must be composed, a query like this is unable to be properly ordered. The results should be pulled from `data`.
|
322 |
|
323 | *Can only be used with collections*
|
324 |
|
325 | ##### orderBy
|
326 |
|
327 | To create a single `orderBy` call, pass a single argument array to `orderBy`
|
328 |
|
329 | ```js
|
330 | {
|
331 | collection: 'cities',
|
332 | orderBy: ['state'],
|
333 | // orderBy: 'state' // string notation can also be used
|
334 | },
|
335 | ```
|
336 |
|
337 | Multiple `orderBy`s are as simple as passing multiple argument arrays (each one representing a `orderBy` call)
|
338 |
|
339 | ```js
|
340 | {
|
341 | collection: 'cities',
|
342 | orderBy: [
|
343 | ['state'],
|
344 | ['population', 'desc']
|
345 | ]
|
346 | },
|
347 | ```
|
348 |
|
349 | *Can only be used with collections*
|
350 |
|
351 | ##### limit
|
352 |
|
353 | Limit the query to a certain number of results
|
354 |
|
355 | ```js
|
356 | {
|
357 | collection: 'cities',
|
358 | limit: 10
|
359 | },
|
360 | ```
|
361 |
|
362 | *Can only be used with collections*
|
363 |
|
364 | ##### startAt
|
365 |
|
366 | > Creates a new query where the results start at the provided document (inclusive)
|
367 |
|
368 | [From Firebase's `startAt` docs](https://firebase.google.com/docs/reference/js/firebase.firestore.CollectionReference#startAt)
|
369 |
|
370 | ```js
|
371 | {
|
372 | collection: 'cities',
|
373 | orderBy: 'population',
|
374 | startAt: 1000000
|
375 | },
|
376 | ```
|
377 |
|
378 | *Can only be used with collections*
|
379 |
|
380 | ##### startAfter
|
381 |
|
382 | > Creates a new query where the results start after the provided document (exclusive)...
|
383 |
|
384 | [From Firebase's `startAfter` docs](https://firebase.google.com/docs/reference/js/firebase.firestore.CollectionReference#startAfter)
|
385 |
|
386 | ```js
|
387 | {
|
388 | collection: 'cities',
|
389 | orderBy: 'population',
|
390 | startAfter: 1000000
|
391 | },
|
392 | ```
|
393 |
|
394 | *Can only be used with collections*
|
395 |
|
396 | ##### endAt
|
397 |
|
398 | > Creates a new query where the results end at the provided document (inclusive)...
|
399 |
|
400 | [From Firebase's `endAt` docs](https://firebase.google.com/docs/reference/js/firebase.firestore.CollectionReference#endAt)
|
401 |
|
402 |
|
403 | ```js
|
404 | {
|
405 | collection: 'cities',
|
406 | orderBy: 'population',
|
407 | endAt: 1000000
|
408 | },
|
409 | ```
|
410 |
|
411 | *Can only be used with collections*
|
412 |
|
413 | ##### endBefore
|
414 |
|
415 | > Creates a new query where the results end before the provided document (exclusive) ...
|
416 |
|
417 | [From Firebase's `endBefore` docs](https://firebase.google.com/docs/reference/js/firebase.firestore.CollectionReference#endBefore)
|
418 |
|
419 |
|
420 | ```js
|
421 | {
|
422 | collection: 'cities',
|
423 | orderBy: 'population',
|
424 | endBefore: 1000000
|
425 | },
|
426 | ```
|
427 |
|
428 | *Can only be used with collections*
|
429 |
|
430 | ##### storeAs
|
431 |
|
432 | Storing data under a different path within redux is as easy as passing the `storeAs` parameter to your query:
|
433 |
|
434 | ```js
|
435 | {
|
436 | collection: 'cities',
|
437 | where: ['state', '==', 'CA'],
|
438 | storeAs: 'caliCities' // store data in redux under this path instead of "cities"
|
439 | },
|
440 | ```
|
441 |
|
442 | **NOTE:** Usage of `"/"` and `"."` within `storeAs` can cause unexpected behavior when attempting to retrieve from redux state
|
443 |
|
444 |
|
445 | #### Other Firebase Statics
|
446 |
|
447 | Other Firebase statics (such as [FieldValue](https://firebase.google.com/docs/reference/js/firebase.firestore.FieldValue)) are available through the firestore instance:
|
448 |
|
449 | ```js
|
450 | import PropTypes from 'prop-types'
|
451 | import { connect } from 'react-redux'
|
452 | import {
|
453 | compose,
|
454 | withHandlers,
|
455 | withContext,
|
456 | getContext
|
457 | } from 'recompose'
|
458 |
|
459 | const withStore = compose(
|
460 | withContext({ store: PropTypes.object }, () => {}),
|
461 | getContext({ store: PropTypes.object }),
|
462 | )
|
463 |
|
464 | const enhance = compose(
|
465 | withStore,
|
466 | withHandlers({
|
467 | onDoneClick: props => (key, done = true) => {
|
468 | const { firestore } = props.store
|
469 | return firestore.update(`todos/${key}`, {
|
470 | done,
|
471 | updatedAt: firestore.FieldValue.serverTimestamp() // use static from firestore instance
|
472 | }),
|
473 | }
|
474 | })
|
475 | )
|
476 |
|
477 | export default enhance(SomeComponent)
|
478 | ```
|
479 |
|
480 | ### Population
|
481 | Population, made popular in [react-redux-firebase](http://react-redux-firebase.com/docs/recipes/populate.html), also works with firestore.
|
482 |
|
483 |
|
484 | #### Automatic Listeners
|
485 | ```js
|
486 | import { connect } from 'react-redux'
|
487 | import { firestoreConnect, populate } from 'react-redux-firebase'
|
488 | import {
|
489 | compose,
|
490 | withHandlers,
|
491 | lifecycle,
|
492 | withContext,
|
493 | getContext
|
494 | } from 'recompose'
|
495 |
|
496 | const populates = [{ child: 'createdBy', root: 'users' }]
|
497 | const collection = 'projects'
|
498 |
|
499 | const withPopulatedProjects = compose(
|
500 | firestoreConnect((props) => [
|
501 | {
|
502 | collection,
|
503 | populates
|
504 | }
|
505 | ]),
|
506 | connect((state, props) => ({
|
507 | projects: populate(state.firestore, collection, populates)
|
508 | }))
|
509 | )
|
510 | ```
|
511 |
|
512 | #### Manually using setListeners
|
513 | ```js
|
514 | import { withFirestore, populate } from 'react-redux-firebase'
|
515 | import { connect } from 'react-redux'
|
516 | import { compose, lifecycle } from 'recompose'
|
517 |
|
518 | const collection = 'projects'
|
519 | const populates = [{ child: 'createdBy', root: 'users' }]
|
520 |
|
521 | const enhance = compose(
|
522 | withFirestore,
|
523 | lifecycle({
|
524 | componentDidMount() {
|
525 | this.props.firestore.setListener({ collection, populates })
|
526 | }
|
527 | }),
|
528 | connect(({ firestore }) => ({ // state.firestore
|
529 | todos: firestore.ordered.todos,
|
530 | }))
|
531 | )
|
532 | ```
|
533 |
|
534 | #### Manually using get
|
535 | ```js
|
536 | import { withFirestore, populate } from 'react-redux-firebase'
|
537 | import { connect } from 'react-redux'
|
538 | import { compose, lifecycle } from 'recompose'
|
539 |
|
540 | const collection = 'projects'
|
541 | const populates = [{ child: 'createdBy', root: 'users' }]
|
542 |
|
543 | const enhance = compose(
|
544 | withFirestore,
|
545 | lifecycle({
|
546 | componentDidMount() {
|
547 | this.props.store.firestore.get({ collection, populates })
|
548 | }
|
549 | }),
|
550 | connect(({ firestore }) => ({ // state.firestore
|
551 | todos: firestore.ordered.todos,
|
552 | }))
|
553 | )
|
554 | ```
|
555 |
|
556 | ## Config Options
|
557 | Optional configuration options for redux-firestore, provided to reduxFirestore enhancer as optional second argument. Combine any of them together in an object.
|
558 |
|
559 | #### logListenerError
|
560 | Default: `true`
|
561 |
|
562 | Whether or not to use `console.error` to log listener error objects. Errors from listeners are helpful to developers on multiple occasions including when index needs to be added.
|
563 |
|
564 | #### enhancerNamespace
|
565 | Default: `'firestore'`
|
566 |
|
567 | Namespace under which enhancer places internal instance on redux store (i.e. `store.firestore`).
|
568 |
|
569 | #### allowMultipleListeners
|
570 | Default: `false`
|
571 |
|
572 | Whether or not to allow multiple listeners to be attached for the same query. If a function is passed the arguments it receives are `listenerToAttach`, `currentListeners`, and the function should return a boolean.
|
573 |
|
574 | #### preserveOnDelete
|
575 | Default: `null`
|
576 |
|
577 | Values to preserve from state when DELETE_SUCCESS action is dispatched. Note that this will not prevent the LISTENER_RESPONSE action from removing items from state.ordered if you have a listener attached.
|
578 |
|
579 | #### preserveOnListenerError
|
580 | Default: `null`
|
581 |
|
582 | Values to preserve from state when LISTENER_ERROR action is dispatched.
|
583 |
|
584 | #### onAttemptCollectionDelete
|
585 | Default: `null`
|
586 |
|
587 | Arguments:`(queryOption, dispatch, firebase)`
|
588 |
|
589 | Function run when attempting to delete a collection. If not provided (default) delete promise will be rejected with "Only documents can be deleted" unless. This is due to the fact that Collections can not be deleted from a client, it should instead be handled within a cloud function (which can be called by providing a promise to `onAttemptCollectionDelete` that calls the cloud function).
|
590 |
|
591 | #### mergeOrdered
|
592 | Default: `true`
|
593 |
|
594 | Whether or not to merge data within `orderedReducer`.
|
595 |
|
596 | #### mergeOrderedDocUpdate
|
597 | Default: `true`
|
598 |
|
599 | Whether or not to merge data from document listener updates within `orderedReducer`.
|
600 |
|
601 |
|
602 | #### mergeOrderedCollectionUpdates
|
603 | Default: `true`
|
604 |
|
605 | Whether or not to merge data from collection listener updates within `orderedReducer`.
|
606 |
|
607 |
|
608 |
|
609 | `redux-firestore`'s enhancer offers a new middleware setup that was not offered in `react-redux-firebase` (but will eventually make it `redux-firebase`)
|
610 | **Note**: This syntax is just a sample and is not currently released
|
611 |
|
612 | ##### Setup
|
613 | ```js
|
614 | ```
|
615 |
|
616 |
|
617 | ##### Usage
|
618 |
|
619 | ```js
|
620 | import { FIREBASE_CALL } from 'redux-firestore'
|
621 |
|
622 | dispatch({
|
623 | type: FIREBASE_CALL,
|
624 | collection: 'users', // only used when namespace is firestore
|
625 | method: 'get' // get method
|
626 | })
|
627 | ```
|
628 |
|
629 | Some of the goals behind this approach include:
|
630 |
|
631 | 1. Not needing to pass around a Firebase instance (with `react-redux-firebase` this meant using `firebaseConnect` HOC or `getFirebase`)
|
632 | 2. Follows [patterns outlined in the redux docs for data fetching](http://redux.js.org/docs/advanced/ExampleRedditAPI.html)
|
633 | 3. Easier to expand/change internal API as Firebase/Firestore API grows & changes -->
|
634 |
|
635 | ## Builds
|
636 |
|
637 | Most commonly people consume Redux Firestore as a [CommonJS module](http://webpack.github.io/docs/commonjs.html). This module is what you get when you import redux in a Webpack, Browserify, or a Node environment.
|
638 |
|
639 | If you don't use a module bundler, it's also fine. The redux-firestore npm package includes precompiled production and development [UMD builds](https://github.com/umdjs/umd) in the [dist folder](https://unpkg.com/redux-firestore@latest/dist/). They can be used directly without a bundler and are thus compatible with many popular JavaScript module loaders and environments. For example, you can drop a UMD build as a `<script>` tag on the page. The UMD builds make Redux Firestore available as a `window.ReduxFirestore` global variable.
|
640 |
|
641 | It can be imported like so:
|
642 |
|
643 | ```html
|
644 | <script src="../node_modules/redux-firestore/dist/redux-firestore.min.js"></script>
|
645 | <!-- or through cdn: <script src="https://unpkg.com/redux-firestore@latest/dist/redux-firestore.min.js"></script> -->
|
646 | <script>console.log('redux firestore:', window.ReduxFirestore)</script>
|
647 | ```
|
648 |
|
649 | Note: In an effort to keep things simple, the wording from this explanation was modeled after [the installation section of the Redux Docs](https://redux.js.org/#installation).
|
650 |
|
651 | ## Applications Using This
|
652 | * [fireadmin.io](http://fireadmin.io) - Firebase Instance Management Tool (source [available here](https://github.com/prescottprue/fireadmin))
|
653 |
|
654 | ## FAQ
|
655 | 1. How do I update a document within a subcollection?
|
656 |
|
657 | Provide `subcollections` config the same way you do while querying:
|
658 |
|
659 | ```js
|
660 | props.firestore.update(
|
661 | {
|
662 | collection: 'cities',
|
663 | doc: 'SF',
|
664 | subcollections: [{ collection: 'counties', doc: 'San Mateo' }],
|
665 | },
|
666 | { some: 'changes' }
|
667 | );
|
668 | ```
|
669 |
|
670 | 1. How do I get auth state in redux?
|
671 |
|
672 | You will most likely want to use [`react-redux-firebase`](https://github.com/prescottprue/react-redux-firebase) or another redux/firebase connector. For more information please visit the [complementary package section](#complementary-package).
|
673 |
|
674 | 1. Are there Higher Order Components for use with React?
|
675 |
|
676 | [`react-redux-firebase`](https://github.com/prescottprue/react-redux-firebase) contains `firebaseConnect`, `firestoreConnect`, `withFirebase` and `withFirestore` HOCs. For more information please visit the [complementary package section](#complementary-package).
|
677 |
|
678 | ## Roadmap
|
679 |
|
680 | * Automatic support for documents that have a parameter and a subcollection with the same name (currently requires `storeAs`)
|
681 | * Support for Passing a Ref to `setListener` in place of `queryConfig` object or string
|
682 |
|
683 | Post an issue with a feature suggestion if you have any ideas!
|
684 |
|
685 | [npm-image]: https://img.shields.io/npm/v/redux-firestore.svg?style=flat-square
|
686 | [npm-url]: https://npmjs.org/package/redux-firestore
|
687 | [npm-downloads-image]: https://img.shields.io/npm/dm/redux-firestore.svg?style=flat-square
|
688 | [quality-image]: http://npm.packagequality.com/shield/redux-firestore.svg?style=flat-square
|
689 | [quality-url]: https://packagequality.com/#?package=redux-firestore
|
690 | [travis-image]: https://img.shields.io/travis/prescottprue/redux-firestore/master.svg?style=flat-square
|
691 | [travis-url]: https://travis-ci.org/prescottprue/redux-firestore
|
692 | [daviddm-image]: https://img.shields.io/david/prescottprue/redux-firestore.svg?style=flat-square
|
693 | [daviddm-url]: https://david-dm.org/prescottprue/redux-firestore
|
694 | [climate-image]: https://img.shields.io/codeclimate/github/prescottprue/redux-firestore.svg?style=flat-square
|
695 | [climate-url]: https://codeclimate.com/github/prescottprue/redux-firestore
|
696 | [coverage-image]: https://img.shields.io/codecov/c/github/prescottprue/redux-firestore.svg?style=flat-square
|
697 | [coverage-url]: https://codecov.io/gh/prescottprue/redux-firestore
|
698 | [license-image]: https://img.shields.io/npm/l/redux-firestore.svg?style=flat-square
|
699 | [license-url]: https://github.com/prescottprue/redux-firestore/blob/master/LICENSE
|
700 | [code-style-image]: https://img.shields.io/badge/code%20style-airbnb-blue.svg?style=flat-square
|
701 | [code-style-url]: https://github.com/airbnb/javascript
|
702 | [gitter-image]: https://img.shields.io/gitter/room/redux-firestore/gitter.svg?style=flat-square
|
703 | [gitter-url]: https://gitter.im/redux-firestore/Lobby
|