Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/dtinth/fiery
π₯ Easy declarative modern Firebase binding for React ^_^
https://github.com/dtinth/fiery
firebase typescript umd
Last synced: 2 days ago
JSON representation
π₯ Easy declarative modern Firebase binding for React ^_^
- Host: GitHub
- URL: https://github.com/dtinth/fiery
- Owner: dtinth
- License: mit
- Created: 2017-11-07T10:49:06.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2022-12-03T15:54:21.000Z (almost 2 years ago)
- Last Synced: 2024-10-29T23:07:19.305Z (16 days ago)
- Topics: firebase, typescript, umd
- Language: TypeScript
- Homepage: https://dtinth.github.io/fiery/
- Size: 660 KB
- Stars: 60
- Watchers: 4
- Forks: 7
- Open Issues: 16
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# [fiery](https://dtinth.github.io/fiery/) π₯
fiery π₯ is the quickest and easiest way to use **Firebase Authentication** and **Firebase Realtime Database** in a React app. It uses latest React features and patterns such as [render props](https://reactjs.org/docs/render-props.html), [hooks](https://reactjs.org/docs/hooks-intro.html), and [suspense](https://reactjs.org/docs/react-api.html#reactsuspense).
**Jump to:** [Installation](#installation) Β· [Demo](#demo) Β· [API Usage](#api-usage) Β· [Development](#development) Β· [License](#license)
_Not production-ready:_ Although I tested it in my projects and small real-world scenarios, they are only small apps and quick prototypes. Contributions are welcome to make this more suitable for production usage.
## Installation
You can install fiery π₯ from npm:
```
npm install --save fiery
```If youβre using [Create React App](https://reactjs.org/docs/create-a-new-react-app.html#create-react-app) or a module bundler such as webpack or parcel, you can import fiery using the `import` statement:
```
import fiery from 'fiery'
```If youβre [using React with no build tooling](https://reactjs.org/docs/add-react-to-a-website.html), a UMD version is also available (make sure to include `react`, `react-dom`, and `firebase` before including `fiery`):
```
```
**Important:** Make sure you are using a version of React that supports the [Hooks API](https://reactjs.org/docs/hooks-intro.html).
## Demo
[Try it out!](https://dtinth.github.io/fiery/#DistributedCounter)
```js
// Demo: DistributedCounter
// This demo app uses only Functional Components!// Normal Firebase stuff...
//
const counterRef = firebase.database().ref('demos/counter')
const counterDecrement = () => counterRef.transaction(c => c - 1)
const counterIncrement = () => counterRef.transaction(c => c + 1)function DistributedCounter() {
// The `useFirebaseDatabase` hook makes this component automatically
// subscribe to Firebase Realtime Database. When the data change,
// this component is automatically re-rendered.
//
// This is possible thanks to the Hooks API, introduced in React 16.7.0-alpha.0.
//
const counterState = fiery.useFirebaseDatabase(counterRef)
return (
-
{counterState.loading ? (
) : counterState.failed ? (
) : (
{counterState.data}
)}
+
)
}ReactDOM.render(
,
document.getElementById('DistributedCounter')
)
``````js
// Demo: GuestbookApp
// This demo app uses only Functional Components!
function GuestbookApp() {
return (
)
}/**
* The navigation bar
*/
function Nav() {
return (
{/* Subscribe to the authentication state.
NOTE: We use the Render Props technique here to localize updates
to a single component without requiring a new
React component. */}
{/* `authState` contains `loading`, `failed`, and `data` properties. */}
{authState =>
authState.loading ? (
) : authState.failed ? (
) : authState.data ? (
) : (
)
}
)
}// The `signIn` and `signOut` functions uses the normal Firebase auth functions.
// No new APIs to learn here!
//
function signIn() {
firebase
.auth()
.signInWithPopup(new firebase.auth.GithubAuthProvider())
.catch(e => window.alert(`Sorry, cannot sign in! ${e}`))
}
function signOut() {
if (window.confirm('RLY SIGN OUT?')) firebase.auth().signOut()
}/**
* The list of guestbook entries.
*/
function GuestbookList() {
// The `useFirebaseDatabase` hook makes this component automatically
// subscribe to Firebase Realtime Database. When the data change,
// this component is automatically re-rendered.
//
const guestbookState = fiery.useFirebaseDatabase(
firebase
.database()
.ref('demos/guestbook')
.orderByChild('time')
.limitToLast(8)
)
return (
{guestbookState.loading ? (
) : guestbookState.failed ? (
) : (
Object.keys(guestbookState.data).map(key => (
))
)}
)
}/**
* The form to submit a guestbook entry.
*/
function GuestbookForm() {
// The `useFirebaseAuth` hook makes this component automatically
// subscribe to Firebase Authentication state. When user signs in
// or signs out, this component will automatically update.
//
const userState = fiery.useFirebaseAuth()
return userState.loading ? (
) : userState.failed ? (
) : userState.data ? (
submitForm(text, userState.data)} />
) : (
)
}// Write to Firebase Realtime Database using the familiar Firebase SDK!
//
function submitForm(text, user) {
return firebase
.database()
.ref('demos/guestbook')
.push({
time: firebase.database.ServerValue.TIMESTAMP,
name: user.displayName,
text: text
})
}// Render the app...
//
ReactDOM.render(, document.getElementById('GuestbookApp'))
``````js
// Demo: SuspenseDemo
// In this demo, there are no checks for Loading/Error state.
// Loading state is handled by React.Suspense.
// Error state is handled by using an Error Boundary.
// WARNING: Unstable API!function SuspenseDemo() {
return (
// Set up an Error Boundary to catch errors.
)
}function SectionSelector() {
// `error` β always results in an error.
// `protected` β only logged in users can see. If you log out, you will get en error.
// `even` β only accessible when the Counter (1st demo) contains an even number.
const sections = ['intro', 'bridge', 'chorus', 'error', 'protected', 'even']
const [currentSection, setCurrentSection] = React.useState('intro')
return (
setCurrentSection(tab)}
/>
{/* Use `React.Suspense` to display a loading UI
if any child component is not ready to render */}
}>
)
}function SectionContent({ sectionName }) {
const dataRef = firebase.database().ref(`demos/tabs/${sectionName}`)
const dataState = fiery.useFirebaseDatabase(dataRef)return (
{/* Use `.unstable_read()` to read the data out of Firebase.
Suspends rendering if data is not ready. */}
{sectionName}: {dataState.unstable_read()}
)
}ReactDOM.render(, document.getElementById('SuspenseDemo'))
```## API Usage
fiery π₯ provides both [hooks](https://reactjs.org/hooks)-based and [render props](https://reactjs.org/docs/render-props.html)-based APIs ([rationale](https://twitter.com/dtinth/status/1055874999377047553)). These APIs will inject **DataState objects** into your component.
A **DataState object** will contain `loading`, `failed`, `data`, `error`, and `retry` properties. It also contains an _experimental_ method `unstable_read()` to make React [suspend](https://reactjs.org/docs/react-api.html#reactsuspense) rendering until the data is loaded.
### Synopsis
- Using Hooks
```js
function HookSynopsis() {
const counterState = fiery.useFirebaseDatabase(counterRef)if (counterState.loading) {
return
} else if (counterState.failed) {
return (
)
} else {
return counterState.data
}
}
```- Suspense + Hooks
```js
function SuspenseHookSynopsis() {
const counterState = fiery.useFirebaseDatabase(counterRef)return counterState.unstable_read()
}
```- Using Render Props
```js
function RenderPropsSynopsis() {
return (
{counterState =>
counterState.loading ? (
) : counterState.failed ? (
) : (
counterState.data
)
}
)
}
```- Suspense + Render Props
```js
function SuspenseRenderPropsSynopsis() {
return (
{counterState => counterState.unstable_read()}
)
}
```### `fiery.useFirebaseAuth()`
Subscribe and use authentication state.
- Returns a `fiery.DataState` wrapping a [`firebase.User`](https://firebase.google.com/docs/reference/js/firebase.User) object (if signed in) or `null` (if signed out).
### `fiery.Auth`
Render prop version of `fiery.useFirebaseAuth`.
Takes a single prop:
- `children` β A **function** that determines how the authentication state should be rendered.
It will be called with a `RemoteDataState` wrapping a [`firebase.User`](https://firebase.google.com/docs/reference/js/firebase.User) object (if signed in) or `null` (if signed out).### `fiery.useFirebaseDatabase(dataRef: firebase.database.Query)`
Subscribe and use data from Firebase Realtime Database.
- `dataRef` β A [`firebase.database.Reference`](https://firebase.google.com/docs/reference/js/firebase.database.Reference) representing the data reference to fetch.
- Returns a `fiery.DataState` wrapping the data (if it exists) or `null` otherwise.### `fiery.Data`
Render prop version of `fiery.useFirebaseDatabase`.
Takes two props:
- `dataRef` β A [`firebase.database.Reference`](https://firebase.google.com/docs/reference/js/firebase.database.Reference) representing the data reference to fetch.
- `children` β A **function** that determines how the data state should be rendered.
It will be called with a `fiery.DataState` wrapping the data (if it exists) or `null` otherwise.### `fiery.DataState` β Representing remote data.
When displaying data from remote sources, the data may not be immediately available β it may still be loading, or may have failed to load.
fiery π₯ represents this by providing you a `DataState` object, which is a plain JS object with these properties:
- `loading` β A **boolean** representing whether data is being actively loaded or not.
- `failed` β A **boolean** representing whether data failed to load or not. **Note:** When retrying, the `failed` flag will stay `true` until new data has been loaded successfully.
- `data` β The data of type **T**. May be `undefined` if `loading || failed`.
- `error` β The **Error**. May be `undefined` if `!failed`.
- `retry` β A **function** that may be called to retry the operation. May be `undefined` if `!failed || loading`.If you use TypeScript, our typings file can help preventing you from accessing the `data` in loading or failed state. Refer to this table.
| `loading` | `failed` | `data` | `error` | `retry` | Remarks |
| --------- | -------- | --------------- | ----------- | ------------ | ------------ |
| `true` | `false` | `T | undefined` | `undefined` | `undefined` | Initial load |
| `true` | `true` | `T | undefined` | `Error` | `undefined` | Retrying |
| `false` | `false` | `T` | `undefined` | `undefined` | Completed |
| `false` | `true` | `T | undefined` | `Error` | `() => void` | Error |**Suspense support:** A DataState object also contains an _experimental_ method, `unstable_read()` for reading the data while rendering. It [suspends rendering](https://reactjs.org/docs/react-api.html#reactsuspense) if data from Firebase is not ready. Note that this uses an _unstable_ API and is subject to change.
### Looking for Firebase Firestore bindings?
Please contribute!
## Development
This project uses Yarn.
### Dependencies
To install dependencies, run:
```
yarn
```### Development
Run:
```
yarn dev
```This will run Rollup in watch mode and generate `umd/fiery.js`.
It will also re-generate the documentation site on change.### Building
To build the library once, run:
```
yarn build
```This will generate `umd/fiery.js`.
### Docs
The documentation website is generated from `README.md`.
To generate the docs, run:
```
yarn docs
```## License
MIT.