React bindings for Firebase and Redux Higher Order Component (HOC) for using Firebase with React and Redux
View deployed version of Material Example here
- Integrated into redux
- Support for updating and nested props
- Population capability (similar to mongoose's
populateor SQL'sJOIN) - Out of the box support for authentication (with auto load user profile)
- Firebase Storage Support
- Support small data ( using
value) or large datasets ( usingchild_added,child_removed,child_changed) - queries support (
orderByChild,orderByKey,orderByValue,orderByPriority,limitToLast,limitToFirst,startAt,endAt,equalToright now ) - Automatic binding/unbinding
- Declarative decorator syntax for React components
redux-thunkIntegration- Firebase v3+ support
npm install --save react-redux-firebaseInstall peer dependencies: npm i --save redux react-redux
Though they are optional, it is highly recommended that you used decorators with this library. The Simple Example shows implementation without decorators, while the Decorators Example shows the same application with decorators implemented.
A side by side comparison using react-redux's connect function/HOC is the best way to illustrate the difference:
class SomeComponent extends Component {
}
export default connect()(SomeComponent)vs.
@connect()
export default class SomeComponent extends Component {
}In order to enable this functionality, you will most likely need to install a plugin (depending on your build setup). For Webpack and Babel, you will need to make sure you have installed and enabled babel-plugin-transform-decorators-legacy by doing the following:
- run
npm i --save-dev babel-plugin-transform-decorators-legacy - Add the following line to your
.babelrc:
{
"plugins": ["transform-decorators-legacy"]
}
Include reduxFirebase in your store compose function:
import { createStore, combineReducers, compose } from 'redux'
import { reduxFirebase, firebaseStateReducer } from 'react-redux-firebase'
// Add Firebase to reducers
const rootReducer = combineReducers({
firebase: firebaseStateReducer
})
// Firebase config
const config = {
apiKey: '<your-api-key>',
authDomain: '<your-auth-domain>',
databaseURL: '<your-database-url>',
storageBucket: '<your-storage-bucket>'
}
// Add redux Firebase to compose
const createStoreWithFirebase = compose(
reduxFirebase(config, { userProfile: 'users' }),
)(createStore)
// Create store with reducers and initial state
const store = createStoreWithFirebase(rootReducer, initialState)In components:
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import { firebase, helpers } from 'react-redux-firebase'
const { isLoaded, isEmpty, dataToJS } = helpers
// Can be used if firebase is used elsewhere
// import { firebaseConnect } from 'react-redux-firebase'
// @firebaseConnect( [
// '/todos'
// ])
@firebase( [
'/todos'
// { type: 'once', path: '/todos' } // for loading once instead of binding
])
@connect(
({firebase}) => ({
todos: dataToJS(firebase, '/todos'),
})
)
class Todos extends Component {
static propTypes = {
todos: PropTypes.object,
firebase: PropTypes.object
}
render() {
const { firebase, todos } = this.props;
// Add a new todo to firebase
const handleAdd = () => {
const {newTodo} = this.refs
firebase.push('/todos', { text:newTodo.value, done:false })
newTodo.value = ''
}
// Build Todos list if todos exist and are loaded
const todosList = !isLoaded(todos)
? 'Loading'
: isEmpty(todos)
? 'Todo list is empty'
: Object.keys(todos).map(
(key, id) => (
<TodoItem key={key} id={id} todo={todos[key]}/>
)
)
return (
<div>
<h1>Todos</h1>
<ul>
{todosList}
</ul>
<input type="text" ref="newTodo" />
<button onClick={handleAdd}>
Add
</button>
</div>
)
}
}
export default TodosAlternatively, if you choose not to use decorators:
const wrappedTodos = firebase([
'/todos'
])(Todos)
export default connect(
({firebase}) => ({
todos: dataToJS(firebase, '/todos'),
})
)(wrappedTodos)See API Docs
A simple example that was created using create-react-app's. Shows a list of todo items and allows you to add to them.
The simple example implemented using decorators built from the output of create-react-app's eject command. Shows a list of todo items and allows you to add to them.
An example that user Material UI built on top of the output of create-react-app's eject command. Shows a list of todo items and allows you to add to them. This is what is deployed to react-redux-firebase.firebaseapp.com.
If you user using redux-thunk, make sure to set up your thunk middleware using it's redux-thunk's withExtraArgument method so that firebase is available within your actions. Here is an example createStore function that adds getFirebase as third argument along with a thunk that uses it:
createStore:
import { applyMiddleware, compose, createStore } from 'redux';
import thunk from 'redux-thunk';
import { reduxReactFirebase, getFirebase } from 'react-redux-firebase';
import makeRootReducer from './reducers';
const fbConfig = {} // your firebase config
const store = createStore(
makeRootReducer(),
initialState,
compose(
applyMiddleware([
thunk.withExtraArgument(getFirebase) // Pass getFirebase function as extra argument
]),
reduxReactFirebase(fbConfig, { userProfile: 'users', enableLogging: false })
)
);Action:
const sendNotification = (payload) => {
type: NOTIFICATION,
payload
}
export const addTodo = (newTodo) =>
(dispatch, getState, getFirebase) => {
const firebase = getFirebase()
firebase
.push('todos', newTodo)
.then(() => {
dispatch(sendNotification('Todo Added'))
})
};generator-react-firebase uses react-redux-firebase when opting to include redux
- How is this different than
redux-react-firebase?
This library was actually originally forked from redux-react-firebase, but adds extended functionality such as:
- populate functionality (similar to mongoDB or SQL JOIN)
profileDecorator- change format of profile stored on FirebasegetFirebase- access to firebase instance that fires actions when methods are called- capability for thunk integration - using
getFirebaseandthunk.withExtraArgument - access to firebase's
storagemethod uniqueSetmethod helper for only setting if location doesn't already exist
I am in the process of writing up an article comparing the two, including the difference in defaults/utils. Maybe a section should be included in the docs as well?
Also, I have been talking to the author of redux-react-firebase about combining, but we are not sure that the users of both want that at this point. Join us on the redux-firebase gitter if you haven't already since a ton of this type of discussion goes on there.
Bottom line: The author of redux-react-firebase was absent when functionality was needed by me and others, so this library was created.
- Why use redux if I have Firebase to store state?
This isn't a super quick answer, so I wrote up a medium article to explain
Special thanks to Tiberiu Craciun for creating redux-react-firebase, which this project is heavily based on.