@taraai/read-write
Version:
Synchronous NoSQL/Firestore for React
80 lines (72 loc) • 2.72 kB
JavaScript
import { isEqual } from 'lodash'
import { useRef, useMemo, useEffect } from 'react'
import { invokeArrayQuery, getChanges } from './utils'
import useFirestore from './useFirestore'
/**
* @description React hook that automatically listens/unListens
* to provided Cloud Firestore paths. Make sure you have required/imported
* Cloud Firestore, including it's reducer, before attempting to use.
* Populate is supported for Firestore as of v0.6.0 of redux-firestore (added
* [as part of issue #48](https://github.com/prescottprue/redux-firestore/issues/48)).
* @param {Array|Function} queriesConfigs - An object, string,
* or array of object or string for paths to sync from firestore. Can also be
* a function that returns the object, string, or array of object or string.
* @see https://react-redux-firebase.com/docs/api/useFirestoreConnect.html
* @example <caption>Basic</caption>
* import React from 'react'
* import { useSelector } from 'react-redux'
* import { useFirestoreConnect } from 'react-redux-firebase'
*
* export default function TodosList() {
* useFirestoreConnect(['todos']) // sync todos collection from Firestore into redux
* const todos = useSelector(state => state.firestore.data.todos)
* return (
* <ul>
* {todos &&
* todos.map((todo) => (
* <li>id: {todo.id} todo: {todo.description}</li>
* ))}
* </ul>
* )
* }
* @example <caption>Object as query</caption>
* import React from 'react'
* import { useSelector } from 'react-redux'
* import { useFirestoreConnect } from 'react-redux-firebase'
*
* export default function TodoItem({ todoId }) {
* useFirestoreConnect([{
* collection: 'todos',
* doc: todoId
* }])
* const todo = useSelector(
* ({ firestore: { data } }) => data.todos && data.todos[todoId]
* )
*
* return <div>{JSON.stringify(todo)}</div>
* }
*/
export default function useFirestoreConnect(queriesConfigs) {
const firestore = useFirestore()
const firestoreIsEnabled = !!firestore
const queryRef = useRef()
const data = useMemo(() => invokeArrayQuery(queriesConfigs), [queriesConfigs])
useEffect(() => {
if (firestoreIsEnabled && !isEqual(data, queryRef.current)) {
const changes = getChanges(data, queryRef.current)
queryRef.current = data
// Remove listeners for inactive subscriptions
firestore.unsetListeners(changes.removed)
// Add listeners for new subscriptions
firestore.setListeners(changes.added)
}
}, [data])
// Emulate componentWillUnmount
useEffect(() => {
return () => {
if (firestoreIsEnabled && queryRef.current) {
firestore.unsetListeners(queryRef.current)
}
}
}, [])
}