Include firebaseReducer
(reducer) while creating your redux store then pass dispatch and your firebase instance to ReactReduxFirebaseProvider
(context provider):
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import firebase from 'firebase/app'
import 'firebase/database'
import 'firebase/auth'
// import 'firebase/firestore' // <- needed if using firestore
// import 'firebase/functions' // <- needed if using httpsCallable
import { createStore, combineReducers, compose } from 'redux'
import {
ReactReduxFirebaseProvider,
firebaseReducer
} from 'react-redux-firebase'
// import { createFirestoreInstance, firestoreReducer } from 'redux-firestore' // <- needed if using firestore
const fbConfig = {}
// react-redux-firebase config
const rrfConfig = {
userProfile: 'users'
// useFirestoreForProfile: true // Firestore for Profile instead of Realtime DB
}
// Initialize firebase instance
firebase.initializeApp(fbConfig)
// Initialize other services on firebase instance
// firebase.firestore() // <- needed if using firestore
// firebase.functions() // <- needed if using httpsCallable
// Add firebase to reducers
const rootReducer = combineReducers({
firebase: firebaseReducer
// firestore: firestoreReducer // <- needed if using firestore
})
// Create store with reducers and initial state
const initialState = {}
const store = createStore(rootReducer, initialState)
const rrfProps = {
firebase,
config: rrfConfig,
dispatch: store.dispatch
// createFirestoreInstance // <- needed if using firestore
}
// Setup react-redux so that connect HOC can be used
function App() {
return (
<Provider store={store}>
<ReactReduxFirebaseProvider {...rrfProps}>
<Todos />
</ReactReduxFirebaseProvider>
</Provider>
)
}
render(<App />, document.getElementById('root'))
The Firebase instance can then be grabbed from context within your components (withFirebase
and firebaseConnect
Higher Order Components provided to help):
Add Data
import React from 'react'
import { useFirebase } from 'react-redux-firebase'
export default function Todos() {
const firebase = useFirebase()
function addSampleTodo() {
const sampleTodo = { text: 'Sample', done: false }
return firebase.push('todos', sampleTodo)
}
return (
<div>
<h1>New Sample Todo</h1>
<button onClick={addSampleTodo}>Add</button>
</div>
)
}
Load Data (listeners automatically managed on mount/unmount)
import React from 'react'
import PropTypes from 'prop-types'
import { useSelector } from 'react-redux'
import { useFirebaseConnect, isLoaded, isEmpty } from 'react-redux-firebase'
export default function Todos() {
useFirebaseConnect([
'todos' // { path: '/todos' } // object notation
])
const todos = useSelector((state) => state.firebase.ordered.todos)
if (!isLoaded(todos)) {
return <div>Loading...</div>
}
if (isEmpty(todos)) {
return <div>Todos List Is Empty</div>
}
return (
<div>
<ul>
{Object.keys(todos).map((key, id) => (
<TodoItem key={key} id={id} todo={todos[key]} />
))}
</ul>
</div>
)
}
Queries Based On Route Params
It is common to make a detail page that loads a single item instead of a whole list of items. A query for a specific Todos
can be created using
import React from 'react'
import PropTypes from 'prop-types'
import { get } from 'lodash'
import { useSelector } from 'react-redux'
import { useFirebaseConnect, useFirebase } from 'react-redux-firebase'
import { useParams } from 'react-router-dom'
export default function Todo() {
const { todoId } = useParams() // matches todos/:todoId in route
const firebase = useFirebase()
useFirebaseConnect([
{ path: `todos/${todoId}` } // create todo listener
// `todos/${todoId}` // equivalent string notation
])
const todo = useSelector(
({ firebase: { data } }) => data.todos && data.todos[todoId]
)
function updateTodo() {
return firebase.update(`todos/${params.todoId}`, { done: !todo.isDone })
}
return (
<div>
<input
name="isDone"
type="checkbox"
checked={todo.isDone}
onChange={updateTodo}
/>
<span>{todo.label}</span>
</div>
)
}
Load Data On Click
import React from 'react'
import { useSelector } from 'react-redux'
import { useFirebase, isLoaded, isEmpty } from 'react-redux-firebase'
function TodosList() {
const todos = useSelector((state) => state.firebase.ordered.todos)
if (!isLoaded(todos)) {
return <div>Loading...</div>
}
if (isEmpty(todos)) {
return <div>Todos List Is Empty</div>
}
return (
<ul>
{Object.keys(todos).map((key, id) => (
<TodoItem key={key} id={id} todo={todos[key]} />
))}
</ul>
)
}
export default function Todos() {
const firebase = useFirebase()
return (
<div>
<h1>Todos</h1>
<EnhancedTodosList />
<button onClick={() => firebase.watchEvent('value', 'todos')}>
Load Todos
</button>
</div>
)
}