react-stateful-firestore

0.5.3 • Public • Published

React Stateful Firestore build status npm version npm downloads

Provides bindings for authentication, Firestore, messaging, and storage data in React. Caches Firestore and authentication with Redux to prevent lag on data that has already been queried. Updates in real-time by default.

Key Goals

  • No new query language: uses Firestore queries, collections, etc.
  • Minimal setup
  • Speed
  • Stateful cache with real-time updating
  • Secure

Quick Start

npm install react-stateful-firestore
# or 
yarn add react-stateful-firestore

Set up Firebase

Install the Firebase dependencies:

yarn add @firebase/app \
  @firebase/auth \
  @firebase/firestore \
  @firebase/messaging \
  @firebase/storage
# or 
npm install --save @firebase/app \
  @firebase/auth \
  @firebase/firestore \
  @firebase/messaging \
  @firebase/storage

Note: We install these packages independently instead of firebase to substantially reduce your final bundle size. You can still use firebase if you want, but it's not recommended.

Next, initialize your Firebase app.

import app from '@firebase/app';
 
const myApp = app.initializeApp({
  apiKey: '<API_KEY>',
  authDomain: '<DOMAIN>',
  databaseURL: '<DB_URL>',
  projectId: '<PROJECT_ID>',
  storageBucket: '<STORAGE_BUCKET>',
  messagingSenderId: '<MESSAGE_ID>'
});

Provide the store

Once your firebase application is initialized, create the React-Stateful-Firestore instance and render it in the Provider component.

import initReactFirestore, { Provider } from 'react-stateful-firestore';
 
initReactFirestore(myApp).then((store) => {
  ReactDOM.render(
    <Provider store={store}>
      <App />
    </Provider>,
    document.getElementById('#root')
  );
});

API

Default Export: initReactFirestore Other Exports:

import initReactFirestore, {
  connect,
  connectAuth,
  FetchStatus,
  Provider,
  resolveFetchStatus,
  resolveInitialFetchStatus
} from 'react-stateful-firestore';

initReactFirestore(app, userCollection?)

This method initializes the backing store and authentication handling for your firebase/firestore application.

argument type description
@param app firebase.app.App Your firebase app, created with firebase.initializeApp
@param userCollection string? Optional. The collection name of where you store extra data about users. If provided, data will appear on the authUserDoc property provided by connectAuth.
@return Promise<store> A promise providing a store object to send to the Provider component

Example:

import initReactFirestore, { Provider } from 'react-stateful-firestore';
 
initReactFirestore(app).then((store) => {
  ReactDOM.render(
    <Provider store={store}>
      <App />
    </Provider>,
    document.getElementById('#root')
  );
});

<Provider store={store}>

This component is necessary to use connect and connectAuth within your application. It provides your Firebase app's instance and special data selectors used internally. It must be provided the store prop, as returned in the promise from initReactFirestore.

connect(getSelectors)

This is a higher order component creator function used to connect your components to data from your Firestore. It accepts a single argument, getSelectors.

Aside from your defined props in getSelectors, connect will also provide the following props to your component:

prop type description
auth firebase.auth.Auth Your app's firebase.auth instance
firestore firebase.firestore.Firestore Your app's firebase.firestore instance
messaging firebase.messaging.Messaging Your app's firebase.messaging
storage firebase.storage.Storage Your app's firebase.storage

Example:

import { connect } from 'react-stateful-firestore';
 
class Article extends Component {
  static propTypes = {
    article: shape({
      error: any,
      fetchStatus: oneOf(['none', 'loading', 'loaded', 'failed']).isRequired, // $Values<typeof FetchStatus>
      doc: object // NOTE: `select(firestore.doc(...))` will provide `doc` (singular)
    }).isRequired,
    articleId: string.isRequired,
    comments: shape({
      error: any,
      fetchStatus: oneOf(['none', 'loading', 'loaded', 'failed']).isRequired, // $Values<typeof FetchStatus>
      docs: arrayOf(object) // NOTE: `select(firestore.collection(...))` will provide `docs` (plural)
    }).isRequired,
    promoImage: shape({
      error: any,
      fetchStatus: oneOf(['none', 'loading', 'loaded', 'failed']).isRequired, // $Values<typeof FetchStatus>,
      downloadUrl: string
    }),
    // Automatically provided by `connect()`
    auth: object.isRequired,
    firestore: object.isRequired,
    messaging: object.isRequired,
    storage: object.isRequired
  };
 
  render() { ... }
}
 
export default connect((select, { firestore, storage }, props) => ({
  article: select(firestore.doc(`articles/${props.articleId}`)),
  comments: select(firestore.collection('comments').where('articleId', '==', props.articleId)),
  promoImage: select(storage.ref('promoimage.jpg'))
}))(Article);
 
// render(<ConnectedArticle articleId="123" />);

getSelectors(select, apis, props)

A function that returns a map of props to data selectors supplied to your final rendered component.

argument type description
@param select Select A function that selects data from Firestore and/or Storage
@param apis SelectApis Your app's firebase APIs
@param props object The props provided to your component
@return object A map of selectors to prop names

Select

argument type description example
@param ref firebase.firestore.DocumentReference or firebase.firestore.CollectionReference of firebase.storage.Storage A Document or Collection reference to your Firestore data or a reference to a Storage item firestore.doc('users/123'); or firestore.collection('users'); or storage.ref('thing')
@param options SelectOptions? Options for the selector { subscribe: false } or { metadata: true }
@return function

SelectApis

prop type description
auth firebase.auth.Auth Your app's firebase.auth instance
firestore firebase.firestore.Firestore Your app's firebase.firestore instance
messaging firebase.messaging.Messaging Your app's firebase.messaging
storage firebase.storage.Storage Your app's firebase.storage

SelectOptions

prop type default description
subscribe boolean true Firestore-only. Add a subscription/listener for Firestore changes. When true (default), we will add a listener for database changes and update them as they happen.
metadata boolean false Storage-only. Get the full metadata of the stored object.

connectAuth(handleAuthState)

This is a higher order component creator function used to connect your components to authentication state from your Firestore. It accepts a single argument, handleAuthState.

connectAuth can be used as a gating function to require an authentication status to determine what should be rendered and how to handle authentication state changes.

prop type description
authUserDoc object? If not logged in: undefined
If no userCollection provided to initReactFirestore: empty object ({})
Otherwise when userCollection is provided: an object containing the data from the document at ${userCollection}/${auth.currentUser.uid}
authFetchStatus FetchStatus The fetch status of the user doc
auth firebase.auth.Auth Your app's firebase.auth instance
firestore firebase.firestore.Firestore Your app's firebase.firestore instance
messaging firebase.messaging.Messaging Your app's firebase.messaging
storage firebase.storage.Storage Your app's firebase.storage
import { connectAuth } from 'react-stateful-firestore';
 
class LoginPage extends Component {
  static propTypes = {
    authUserDoc: object,
    authFetchStatus: oneOf(['none', 'loading', 'loaded', 'failed']).isRequired,
    // Also provided by `connectAuth()`
    auth: object.isRequired, // Use this to access the auth user, `auth.currentUser`
    firestore: object.isRequired,
    messaging: object.isRequired,
    storage: object.isRequired
  };
 
  render() { ... }
}
 
class Loading extends Component {
  render() {
    return 'Loading…';
  }
}
 
export default connectAuth(({ action, doc, fetchStatus }, auth, props) => {
  if (action === 'signin') {
    // If the user becomes signed in, push them to the home page.
    props.history.push('/');
  }
}, Loading)(LoginPage);
 
// render(<ConnectedLoginPage history={history} />);

handleAuthState(state, auth, props)

A custom function that you create, passed to connectAuth to handle the state of authentication within your React application.

argument type description
@param state AuthState The state and state change of user authentication.
@param auth firebase.auth.Auth Your app's firebase.auth instance
@param props object The props provided to your component
@return void

AuthState

key type description
@prop action string? Either undefined (no new action), 'signin' when the user state has changed to signed-in or 'signout' when the user state has changed to signed-out
@prop doc object? The document from firestore including extra data about the logged in user
@prop fetchStatus FetchStatus The fetch status of the doc.

FetchStatus

A string representing the status of the query for a document. One of the following:

key value description
NONE 'none' The document has not started loading yet
LOADING 'loading' The document is currently in the process of loading
LOADED 'loaded' The document has been successfully received
FAILED 'failed' There was an error requesting the document

resolveFetchStatus(...items)

Returns a single FetchStatus value given the state of multiple Collections or Documents. This method requires that all items are loaded before returning FetchStatus.LOADED.

argument type description
@param items Collection or Document

resolveInitialFetchStatus(...items)

Returns a single FetchStatus value given the initial state of multiple Collections or Documents. This method will return FetchStatus.LOADED if any item is loaded.

argument type description
@param items Collection or Document

Types

React Stateful Firestore also exposes a few flow types.

$FetchStatus

A FetchStatus value.

Document

Creates a type for documents provided as props on your connected components.

type MyDocument = Document<{ name: string }>
 
const doc: MyDocument;
console.log(doc.fetchStatus); // -> A $FetchStatus
console.log(doc.id); // -> The Firestore document id
console.log(doc.doc); // -> The data in the document on Firestore

Collection

Creates a type for collections provided as props on your connected components

type MyCollection = Collection<{ name: string }>
 
const collection: MyCollection;
console.log(collection.fetchStatus); // -> A $FetchStatus
console.log(collection.docs); // -> Array of Documents

Readme

Keywords

none

Package Sidebar

Install

npm i react-stateful-firestore

Weekly Downloads

2

Version

0.5.3

License

MIT

Unpacked Size

403 kB

Total Files

76

Last publish

Collaborators

  • paularmstrong