0.5.3 • Published 6 years ago

react-stateful-firestore v0.5.3

Weekly downloads
2
License
MIT
Repository
github
Last release
6 years ago

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.

argumenttypedescription
@paramappfirebase.app.AppYour firebase app, created with firebase.initializeApp
@paramuserCollectionstring?Optional. The collection name of where you store extra data about users. If provided, data will appear on the authUserDoc property provided by connectAuth.
@returnPromise<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:

proptypedescription
authfirebase.auth.AuthYour app's firebase.auth instance
firestorefirebase.firestore.FirestoreYour app's firebase.firestore instance
messagingfirebase.messaging.MessagingYour app's firebase.messaging
storagefirebase.storage.StorageYour 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.

argumenttypedescription
@paramselectSelectA function that selects data from Firestore and/or Storage
@paramapisSelectApisYour app's firebase APIs
@parampropsobjectThe props provided to your component
@returnobjectA map of selectors to prop names

Select

argumenttypedescriptionexample
@paramreffirebase.firestore.DocumentReference or firebase.firestore.CollectionReference of firebase.storage.StorageA Document or Collection reference to your Firestore data or a reference to a Storage itemfirestore.doc('users/123'); or firestore.collection('users'); or storage.ref('thing')
@paramoptionsSelectOptions?Options for the selector{ subscribe: false } or { metadata: true }
@returnfunction

SelectApis

proptypedescription
authfirebase.auth.AuthYour app's firebase.auth instance
firestorefirebase.firestore.FirestoreYour app's firebase.firestore instance
messagingfirebase.messaging.MessagingYour app's firebase.messaging
storagefirebase.storage.StorageYour app's firebase.storage

SelectOptions

proptypedefaultdescription
subscribebooleantrueFirestore-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.
metadatabooleanfalseStorage-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.

proptypedescription
authUserDocobject?If not logged in: undefinedIf 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}
authFetchStatusFetchStatusThe fetch status of the user doc
authfirebase.auth.AuthYour app's firebase.auth instance
firestorefirebase.firestore.FirestoreYour app's firebase.firestore instance
messagingfirebase.messaging.MessagingYour app's firebase.messaging
storagefirebase.storage.StorageYour 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.

argumenttypedescription
@paramstateAuthStateThe state and state change of user authentication.
@paramauthfirebase.auth.AuthYour app's firebase.auth instance
@parampropsobjectThe props provided to your component
@returnvoid

AuthState

keytypedescription
@propactionstring?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
@propdocobject?The document from firestore including extra data about the logged in user
@propfetchStatusFetchStatusThe fetch status of the doc.

FetchStatus

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

keyvaluedescription
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.

argumenttypedescription
@paramitemsCollection 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.

argumenttypedescription
@paramitemsCollection 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
0.5.3

6 years ago

0.5.2

6 years ago

0.5.1

6 years ago

0.5.0

6 years ago

0.4.5

6 years ago

0.4.4

6 years ago

0.4.3

6 years ago

0.4.2

6 years ago

0.4.1

6 years ago

0.4.0

6 years ago

0.3.4

6 years ago

0.3.3

6 years ago

0.3.2

6 years ago

0.3.1

6 years ago

0.3.0

6 years ago

0.2.1

6 years ago

0.2.0

6 years ago

0.1.2

6 years ago

0.1.1

6 years ago

0.1.0

6 years ago

0.0.4

6 years ago

0.0.3

6 years ago

0.0.2

6 years ago

0.0.1

6 years ago