UNPKG

14 kBMarkdownView Raw
1[![Build Status][build-badge]][build]
2[![codecov][coverage-badge]][coverage]
3[![MIT License][license-badge]][license]
4[![version][version-badge]][package]
5
6[![size][size-badge]][unpkg-dist]
7[![gzip size][gzip-badge]][unpkg-dist]
8[![module formats: umd, cjs, and es][module-formats-badge]][unpkg-dist]
9
10# react-firestore 🔥🏪
11
12React components to fetch collections and documents from Firestore
13
14## The problem
15
16You want to use the new Firestore database from Google, but don't want to
17have to use redux or any other state management tool. You would like to not have
18to worry too much about the exact API for firestore (snapshots, references, etc),
19and just be able to retrieve collections and documents and read their data.
20
21You also want to do all this using [render props, because they're awesome](https://www.youtube.com/watch?v=BcVAq3YFiuc).
22
23## The solution
24
25This is a set of components that allows you to interact with Firestore collections
26and documents, without needing to constantly call additional methods (like `.data()`)
27to display your data.
28
29There is still an escape hatch where the snapshot from Firestore is provided to
30your render function, in the event that you need more control over your interactions
31with Firestore.
32
33## Disclaimer
34
35This project is still a work in progress and in an alpha state.
36The API may update frequently.
37
38## Table of Contents
39
40<!-- START doctoc generated TOC please keep comment here to allow auto update -->
41
42<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
43
44* [Installation](#installation)
45* [Usage](#usage)
46 * [`FirestoreProvider`](#firestoreprovider)
47 * [`FirestoreCollection`](#firestorecollection)
48 * [`FirestoreDocument`](#firestoredocument)
49 * [`Firestore`](#firestore)
50 * [`withFirestore`](#withfirestore)
51
52<!-- END doctoc generated TOC please keep comment here to allow auto update -->
53
54## Installation
55
56This package is available on [npm][npm].
57
58```
59npm install --save react-firestore
60```
61
62Or, if you're using [yarn][yarn]:
63
64```
65yarn add react-firestore
66```
67
68## Usage
69
70There are 3 components provided with this package:
71
72* [FirestoreProvider](#firestoreprovider)
73* [FirestoreCollection](#firestorecollection)
74* [FirestoreDocument](#firestoredocument)
75
76### `FirestoreProvider`
77
78This component allows the `FirestoreCollection` and `FirestoreDocument`
79components to communicate with Firestore.
80
81At the top level of your app, configure `firebase` and render the
82`FirestoreProvider` component.
83
84If you're using [create-react-app][create-react-app], your `index.js`
85file would look something like this:
86
87
88```jsx
89import React from 'react';
90import ReactDOM from 'react-dom';
91import firebase from '@firebase/app';
92import '@firebase/firestore';
93import { FirestoreProvider } from 'react-firestore';
94
95import App from './App';
96
97const config = {
98 apiKey: '<your_api_key>',
99 projectId: '<your_firebase_project_id>',
100};
101
102firebase.initializeApp(config);
103
104ReactDOM.render(
105 <FirestoreProvider firebase={firebase}>
106 <App />
107 </FirestoreProvider>,
108 document.getElementById('root'),
109);
110```
111
112_Important: Starting with Firebase v5.5.0 timestamp objects stored in Firestore get returned as Firebase
113Timestamp objects instead of regular Date() objects. To make your app compatible with this
114change, add the `useTimestampsInSnapshots` to the FirestoreProvider element. If you dont do this
115your app might break. For more information visit [the Firebase refrence documentation][https://firebase.google.com/docs/reference/js/firebase.firestore.Timestamp]._
116
117_Note: The reason for the separate imports for `@firebase/app` and `@firebase/firestore`
118is because `firestore` is not included in the default `firebase` wrapper package. See
119the [firestore package](https://www.npmjs.com/package/@firebase/firestore) for more details._
120
121#### `FirestoreProvider` props
122
123##### firebase
124
125> `firebase` | _required_
126
127An already initialized `firebase` object from the [@firebase/app package](https://www.npmjs.com/package/@firebase/app).
128
129### `FirestoreCollection`
130
131This component allows you to interact with a Firestore collection.
132Using this component, you can access the collection at a given `path`
133and provide sort options, perform queries, and paginate data.
134
135This component will setup a listener and update
136whenever the given collection is updated in Firestore.
137
138Example usage to get a collection and sort by some fields:
139
140```jsx
141<FirestoreCollection
142 path="stories"
143 sort="publishedDate:desc,authorName"
144 render={({ isLoading, data }) => {
145 return isLoading ? (
146 <Loading />
147 ) : (
148 <div>
149 <h1>Stories</h1>
150 <ul>
151 {data.map(story => (
152 <li key={story.id}>
153 {story.title} - {story.authorName}
154 </li>
155 ))}
156 </ul>
157 </div>
158 );
159 }}
160/>
161```
162
163#### `FirestoreCollection` props
164
165##### path
166
167> `string` | _required_
168
169The `/` separated path to the Firestore collection. Collections must
170contain an odd number of path segments.
171
172##### sort
173
174> `string` | defaults to `null`
175
176A comma-delimited list of fields by which the query should be ordered.
177Each item in the list can be of the format `fieldName` or `fieldName:sortOrder`.
178The `sortOrder` piece can be either `asc` or `desc`. If just a field name is given,
179`sortOrder` defaults to `asc`.
180
181##### limit
182
183> `number` | defaults to `null`
184
185The maximum number of documents to retrieve from the collection.
186
187##### filter
188
189> `array` or `array of array` | defaults to `null`
190
191Passing in an array of strings creates a simple query to filter the collection by
192
193```jsx
194<FirestoreCollection
195 path={'users'}
196 filter={['firstName', '==', 'Mike']}
197 render={() => {
198 /* render stuff*/
199 }}
200/>
201```
202
203Passing in an array of arrays creates a compound query to filter the collection by
204
205```jsx
206<FirestoreCollection
207 path={'users'}
208 filter={[['firstName', '==', 'Mike'], ['lastName', '==', 'Smith']]}
209 render={() => {
210 /* render stuff*/
211 }}
212/>
213```
214
215Passing in document references allows you to filter by reference fields:
216
217```jsx
218<FirestoreCollection
219 path={'users'}
220 filter={[
221 'organization',
222 '==',
223 firestore.collection('organizations').doc('foocorp'),
224 ]}
225 render={() => {
226 /* render stuff*/
227 }}
228/>
229```
230
231##### render
232
233> function({}) | _required_
234
235This is the function where you render whatever you want based on the state of
236the `FirebaseCollection` component. The object provided to the `render` function
237contains the following fields:
238
239| property | type | description |
240| --------- | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
241| isLoading | `boolean` | Loading status for the firebase query. `true` until an initial payload from Firestore is received. |
242| error | `Error` | Error received from firebase when the listen fails or is cancelled. |
243| data | `Array<any>` | An array containing all of the documents in the collection. Each item will contain an `id` along with the other data contained in the document. |
244| snapshot | `QuerySnapshot` / `null` | The firestore `QuerySnapshot` created to get data for the collection. See [QuerySnapshot docs](https://cloud.google.com/nodejs/docs/reference/firestore/latest/QuerySnapshot) for more information. |
245
246### `FirestoreDocument`
247
248This component allows you to retrieve a Firestore document from the given `path`.
249
250This component will setup a listener and update
251whenever the given document is updated in Firestore.
252
253```jsx
254<FirestoreDocument
255 path="stories/1"
256 render={({ isLoading, data }) => {
257 return isLoading ? (
258 <Loading />
259 ) : (
260 <div>
261 <h1>{data.title}</h1>
262 <h2>
263 {data.authorName} - {data.publishedDate}
264 </h2>
265 <p>{data.description}</p>
266 </div>
267 );
268 }}
269/>
270```
271
272#### `FirestoreDocument` props
273
274##### path
275
276> `string` | _required_
277
278The `/` separated path to the Firestore document.
279
280##### render
281
282> function({}) | _required_
283
284This is the function where you render whatever you want based on the state of
285the `FirebaseDocument` component. The object provided to the `render` function
286contains the following fields:
287
288| property | type | description |
289| --------- | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
290| isLoading | `boolean` | Loading status for the firebase query. `true` until an initial payload from Firestore is received. |
291| error | `Error` | Error received from firebase when parsing the document data. |
292| data | `Object` / `null` | The document that resides at the given `path`. Will be `null` until an initial payload is received. The document will contain an `id` along with the other data contained in the document. |
293| snapshot | `DocumentSnapshot` / `null` | The firestore `DocumentSnapshot` created to get data for the document. See [DocumentSnapshot docs](https://cloud.google.com/nodejs/docs/reference/firestore/latest/DocumentSnapshot) for more information. |
294
295### `Firestore`
296
297This component supplies the firestore database to the function specified
298by the `render` prop. This component can be used if you need more flexibility
299than the `FirestoreCollection` and `FirestoreDocument` components provide,
300or if you would just rather interact directly with the `firestore` object.
301
302```jsx
303<Firestore
304 render={({ firestore }) => {
305 // Do stuff with `firestore`
306 return <div> /* Component markup */ </div>;
307 }}
308/>
309```
310
311#### `Firestore` props
312
313##### render
314
315> function({}) | _required_
316
317This is the function where you render whatever you want using the firestore
318object passed in.
319
320| property | type | description |
321| --------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
322| firestore | `Object` | The `Firestore` class from [firestore][firestore-package]. See the docs for the [Firestore class][firestore-class-docs] for more information. |
323
324### `withFirestore`
325
326This higher-order component can be used to provide the firestore database
327directly to the wrapped component via the `firestore` prop.
328
329```jsx
330class MyComponent extends Component {
331 state = {
332 story: null,
333 };
334
335 componentDidMount() {
336 const { firestore } = this.props;
337
338 firestore.doc('stories/1').onSnapshot(snapshot => {
339 this.setState({ story: snapshot });
340 });
341 }
342
343 render() {
344 const { story } = this.state;
345 const storyData = story ? story.data() : null;
346
347 return storyData ? (
348 <div>
349 <h1>{storyData.title}</h1>
350 <h2>
351 {storyData.authorName} - {storyData.publishedDate}
352 </h2>
353 <p>{storyData.description}</p>
354 </div>
355 ) : (
356 <Loading />
357 );
358 }
359}
360
361export default withFirestore(MyComponent);
362```
363
364#### `Component.WrappedComponent`
365
366The wrapped component is available as a static property called
367`WrappedComponent` on the returned component. This can be used
368for testing the component in isolation, without needing to provide
369context in your tests.
370
371#### Props for returned component
372
373##### wrappedComponentRef
374
375> function | _optional_
376
377A function that will be passed as the `ref` prop to the wrapped component.
378
379[npm]: https://www.npmjs.com/
380[yarn]: https://yarnpkg.com/
381[firestore-package]: https://www.npmjs.com/package/@firebase/firestore
382[firestore-class-docs]: https://cloud.google.com/nodejs/docs/reference/firestore/0.11.x/Firestore
383[create-react-app]: https://github.com/facebookincubator/create-react-app
384[build-badge]: https://img.shields.io/travis/green-arrow/react-firestore.svg?style=flat-square
385[build]: https://travis-ci.org/green-arrow/react-firestore
386[coverage-badge]: https://img.shields.io/codecov/c/github/green-arrow/react-firestore.svg?style=flat-square
387[coverage]: https://codecov.io/github/green-arrow/react-firestore
388[license-badge]: https://img.shields.io/npm/l/react-firestore.svg?style=flat-square
389[license]: https://github.com/green-arrow/react-firestore/blob/master/LICENSE
390[version-badge]: https://img.shields.io/npm/v/react-firestore.svg?style=flat-square
391[package]: https://www.npmjs.com/package/react-firestore
392[gzip-badge]: http://img.badgesize.io/https://unpkg.com/react-firestore/dist/react-firestore.umd.min.js?compression=gzip&label=gzip%20size&style=flat-square
393[size-badge]: http://img.badgesize.io/https://unpkg.com/react-firestore/dist/react-firestore.umd.min.js?label=size&style=flat-square
394[unpkg-dist]: https://unpkg.com/react-firestore/dist/
395[module-formats-badge]: https://img.shields.io/badge/module%20formats-umd%2C%20cjs%2C%20es-green.svg?style=flat-square