百科.dev
全部条目AI 编程趋势榜开源项目技术资讯提交条目
登录
< 返回工具列表
S

swr-firestore

> 编程语言
开源

在 React/React Native/Expo 应用中,实现 Vercel 的 useSWR 以查询 Firestore。 ‍

778 stars0 点赞0 次浏览
访问官网GitHub

工具介绍

在 React/React Native/Expo 应用中,实现 Vercel 的 useSWR 以查询 Firestore。 ‍

SWR + Firestore

const { data } = useDocument('users/fernando')

It's that easy.

This library provides the hooks you need for querying Firestore, that you can actually use in production, on every screen.

⚡️ It aims to be the fastest way to use Firestore in a React app, both from a developer experience and app performance perspective.

This library is built on top useSWR, meaning you get all of its awesome benefits out-of-the-box.

You can now fetch, add, and mutate Firestore data with zero boilerplate.

Features

  • Shared state / cache between collection and document queries (instead of Redux??)
  • Works with both React and React Native.
  • Offline mode with Expo (without detaching!)
  • Blazing fast
  • Query collection groups (new in 0.14.x!)
  • set, update, and add update your global cache, instantly
  • TypeScript-ready (see docs)
  • Realtime subscriptions (example)
  • Prevent memory leaks from Firestore subscriptions
  • No more parsing document.data() from Firestore requests
  • Server-side rendering (SSR or SSG) with Next.js (example)
  • Automatic date parsing (no more .toDate())
  • Firebase v8 support (see #59)

...along with the features touted by Vercel's incredible SWR library:

"With SWR, components will get a stream of data updates constantly and automatically. Thus, the UI will be always fast and reactive."

  • Transport and protocol agnostic data fetching
  • Fast page navigation
  • Revalidation on focus
  • Interval polling
  • Request deduplication
  • Local mutation
  • Pagination
  • TypeScript ready
  • SSR support
  • Suspense mode
  • Minimal API

⭐️

If you like this library, give it star and let me know on Twitter!

Installation

yarn add @nandorojo/swr-firestore

# or
npm install @nandorojo/swr-firestore

Install firebase:

# if you're using expo:
expo install firebase

# if you aren't using expo:
yarn add firebase
# or
npm i firebase

Set up

In the root of your app, create an instance of Fuego and pass it to the FuegoProvider.

If you're using Firebase v8, see this solution for creating your instance of Fuego.

If you're using next.js, this goes in your pages/_app.js file.

App.js

import React from 'react'
import 'firebase/firestore'
import 'firebase/auth'
import { Fuego, FuegoProvider } from '@nandorojo/swr-firestore'

const firebaseConfig = {
  // put yours here
}

const fuego = new Fuego(firebaseConfig)

export default function App() {
  return (
    
      
    
  )
}

Make sure to create your Fuego instance outside of the component. The only argument Fuego takes is your firebase config variable.

Under the hood, this step initializes firebase for you. No need to call firebase.initializeApp.

Basic Usage

Assuming you've already completed the setup...

Subscribe to a document

import React from 'react'
import { useDocument } from '@nandorojo/swr-firestore'
import { Text } from 'react-native'

export default function User() {
  const user = { id: 'Fernando' }
  const { data, update, error } = useDocument(`users/${user.id}`, {
    listen: true,
  })

  if (error) return Error!
  if (!data) return Loading...

  return Name: {data.name}
}

Get a collection

import React from 'react'
import { useCollection } from '@nandorojo/swr-firestore'
import { Text } from 'react-native'

export default function UserList() {
  const { data, update, error } = useCollection(`users`)

  if (error) return Error!
  if (!data) return Loading...

  return data.map(user => {user.name})
}

useDocument accepts a document path as its first argument here. useCollection works similarly.

Simple examples

Query a users collection:

const { data } = useCollection('users')

Subscribe for real-time updates:

const { data } = useDocument(`users/${user.id}`, { listen: true })

Make a complex collection query:

const { data } = useCollection('users', {
  where: ['name', '==', 'fernando'],
  limit: 10,
  orderBy: ['age', 'desc'],
  listen: true,
})

Pass options from SWR to your document query:

// pass SWR options
const { data } = useDocument('albums/nothing-was-the-same', {
  shouldRetryOnError: false,
  onSuccess: console.log,
  loadingTimeout: 2000,
})

Pass options from SWR to your collection query:

// pass SWR options
const { data } = useCollection(
  'albums',
  {
    listen: true,
    // you can pass multiple where conditions if you want
    where: [
      ['artist', '==', 'Drake'],
      ['year', '==', '2020'],
    ],
  },
  {
    shouldRetryOnError: false,
    onSuccess: console.log,
    loadingTimeout: 2000,
  }
)

Add data to your collection:

const { data, add } = useCollection('albums', {
  where: ['artist', '==', 'Drake'],
})

const onPress = async () => {
  // calling this will automatically update your global cache & Firestore
  const documentId = await add({
    title: 'Dark Lane Demo Tapes',
    artist: 'Drake',
    year: '2020',
  })
}

Set document data:

const { data, set, update } = useDocument('albums/dark-lane-demo-tapes')

const onReleaseAlbum = () => {
  // calling this will automatically update your global cache & Firestore
  set(
    {
      released: true,
    },
    { merge: true }
  )

  // or you could call this:
  update({
    released: true,
  })
}

Use dynamic fields in a request:

If you pass null as the collection or document key, the request won't send.

Once the key is set to a string, the request will send.

Get list of users who have you in their friends list

import { useDoormanUser } from 'react-doorman'

const { uid } = useDoormanUser()
const { data } = useCollection(uid ? 'users' : null, {
  where: ['friends', 'array-contains', uid],
})

Get your favorite song

const me = { id: 'fernando' }

const { data: user } = useDocument(`users/${me.id}`)

// only send the request once the user.favoriteSong exists!
const { data: song } = useDocument(
  user?.favoriteSong ? `songs/${user.favoriteSong}` : null
)

Parse date fields in your documents

Magically turn any Firestore timestamps into JS date objects! No more .toDate().

Imagine your user document schema looks like this:

type User = {
  name: string
  lastUpdated: {
    date: Date
  }
  createdAt: Date
}

In order to turn createdAt and lastUpdated.date into JS objects, just use the parseDates field:

In a document query

const { data } = useDocument('user/fernando', {
  parseDates: ['createdAt', 'lastUpdated.date'],
})

let createdAt: Date
if (data) {
  // ✅ all good! it's a JS Date now.
  createdAt = data.createdAt
}

data.createdAt and data.lastUpdated.date are both JS dates now!

In a collection query

const { data } = useCollection('user', {
  parseDates: ['createdAt', 'lastUpdated.date'],
})

if (data) {
  data.forEach(document => {
    document.createdAt // JS date!
  })
}

For more explanation on the dates, see issue #4.

Access a document's Firestore snapshot

If you set ignoreFirestoreDocumentSnapshotField to false, you can access the __snapshot field.

const { data } = useDocument('users/fernando', {
  ignoreFirestoreDocumentSnapshotField: false, // default: true
})

if (data) {
  const id = data?.__snapshot.id
}

You can do the same for useCollection and useCollectionGroup. The snapshot will be on each item in the data array.

This comes in handy when you are working with forms for data edits:

With Formik

const { data, set } = useDocument('users/fernando', {
  ignoreFirestoreDocumentSnapshotField: false,
})

if (!data) return 

With state and hooks

const { data, set } = useDocument('users/fernando', {
  ignoreFirestoreDocumentSnapshotField: false,
})

const [values, setValues] = useState(null);

useEffect(() => {
  if (data) {
    setValues(data.__snapshot.data());
  }
}, [data]);

Paginate a collection:

Video here.

…

Query Documents

You'll rely on useDocument to query documents.

import React from 'react'
import { useDocument } from '@nandorojo/swr-firestore'

const user = { id: 'Fernando' }
export default () => {
  const { data, error } = useDocument(`users/${user.id}`)
}

If you want to set up a listener (or, in Firestore-speak, onSnapshot) just set listen to true.

const { data, error } = useDocument(`users/${user.id}`, { listen: true })

API

Imports

import {
  useDocument,
  useCollection,
  useCollectionGroup, //  new!
  revalidateDocument,
  revalidateCollection,
  // these all update BOTH Firestore & the local cache ⚡️
  set, // set a firestore document
  update, // update a firestore document
  fuego, // get the firebase instance used by this lib
  getCollection, // prefetch a collection, without being hooked into SWR or React
  getDocument, // prefetch a document, without being hooked into SWR or React
} from '@nandorojo/swr-firestore'

useDocument(path, options)

const {
  data,
  set,
  update,
  deleteDocument,
  error,
  isValidating,
  mutate,
  unsubscribe
} = useDocument(path, options)

Arguments

  • path required The unique document path for your Firestore document.
    • string | null. If null, the request will not be sent. This is useful if you want to get a user document, but the user ID hasn't loaded yet, for instance.
    • This follows the same pattern as the key argument in useSWR. See the SWR docs for more. Functions are not currently supported for this argument.
  • options (optional) A dictionary with added options for the query. Takes the folowing values:
    • listen = false: If true, sets up a listener for this document that updates whenever it changes.
    • You can also pass any of the options available from useSWR.
    • ignoreFirestoreDocumentSnapshotField = true. See elaboration below.
    • parseDates: An array of string keys that correspond to dates in your document. Example.
ignoreFirestoreDocumentSnapshotField

If true, docs returned in data will not include the firestore __snapshot field. If false, it will include a __snapshot field. This lets you access the document snapshot, but makes the document not JSON serializable.

By default, it ignores the __snapshot field. This makes it easier for newcomers to use JSON.stringify without weird errors. You must explicitly set it to false to use it.

// include the firestore document snapshots
const { data } = useDocument('users/fernando', {
  ignoreFirestoreDocumentSnapshotField: false,
})

if (data) {
  const path = data.__snapshot.ref.path
}

The __snapshot field is the exact snapshot returned by Firestore.

See Firestore's snapshot docs for more.

Return values

Returns a dictionary with the following values:

  • set(data, SetOptions?): Extends the firestore document set function.
    • You can call this when you want to edit your document.
    • It also

Issues· 50 开放

查看全部 Issues在 GitHub 打开

暂无开放 Issues,或尚未同步最近议题。

> 标签

TypeScript

暂无评论,来聊聊你的看法吧

> 工具信息

发布日期2026年8月1日
最后更新2026年9月17日
分类编程语言
定价开源

> 相关工具

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言