# :fire: :hatching_chick: {%= name %} {%= badge("fury") %} {%= badge("travis") %} [![Firebase](https://raw.githubusercontent.com/firebase/firebase-chrome-extension/master/icons/icon48.png)](https://www.firebase.com) [![ReactJS](https://raw.githubusercontent.com/facebook/react/master/docs/img/logo_small.png)](https://facebook.github.io/react)

> {%= description %}

{%= badge("npm") %}

Firedux (*fiery·ducks*) wraps the [Firebase][firebase] [JavaScript API](https://www.firebase.com/docs/web/api/)
to dispatch [Redux] actions
that optimisically & immediately read/write to an in-memory
subset of your data from Firebase,
then asynchronously pull & push data in the background.

Also supports some authentication methods and actions.

Works well with [React].

Support firedux and fiery ducks like Magmar!

![Magmar](docs/magmar.gif)

{%/*
## Table of contents
<!-- toc -->
*/%}

## Install
{%= include("install-npm", { save: true }) %}

You'll need to configure `redux-thunk` on your Redux store.

## Use

See [my TodoMVC example](https://github.com/adjohnson916/firedux-todomvc), the [tests](test/index.js), and below:

```js
import Firedux from 'firedux'
import Firebase from 'firebase'
import { createStore, applyMiddleware, combineReducers } from 'redux'
import thunk from 'redux-thunk'

/**
 * For Firebase 2.x, e.g.:
 */
var ref = new Firebase('https://redux-firebase.firebaseio.com/')

/**
 * Or for Firebase 3.x, e.g.:
 */
var app = Firebase.initializeApp({
  apiKey: '<your-api-key>',
  authDomain: '<your-auth-domain>',
  databaseURL: 'https://redux-firebase.firebaseio.com/',
  storageBucket: '<your-storage-bucket>'
})
var ref = app.database()

/**
 * Then create your Firedux instance, passing it your database reference as `ref`.
 */
const firedux = new Firedux({
  ref,

  // Optional:
  omit: ['$localState'] // Properties to reserve for local use and not sync with Firebase.
})

const reducer = combineReducers({
  firedux: firedux.reducer()
  // Your other reducers...
})

// Create store with middleware, including thunk.
const store = applyMiddleware(
  thunk
  // Your other middleware...
)(createStore)(reducer)

// Set dispatch function from store on your Firedux instance.
firedux.dispatch = store.dispatch


// Later, you can subscribe to state.
store.subscribe(() => {
  const state = store.getState()
  const { data, authData } = state.firedux
  console.log('Test data from Firebase:', data.test)

  // Lazy loading
  // e.g. once authorized, get user data:
  if (authData && authData.auth && authData.auth.uid) {
    firedux.watch(`users/${authData.auth.uid}`)
  }
})

// Watch a path:
firedux.watch('users/joe')
.then(({snapshot}) => {})
// state.firedux.data.users.joe
// Note: this promise will only resolve on the first value,
//  but it'll keep syncing on all value updates.

// Get:
firedux.get('posts/123')
.then(({snapshot}) => {})
// state.firedux.data.posts['123']

// Set:
firedux.set('test', true)
.then(({value}) => {})
// state.firedux.data.test == true

// Update (merging set):
firedux.update('users/joe', { job: 'developer' })
.then(({value}) => {})
// state.firedux.data.users.joe == { name: 'Joe', job: 'developer' }

// Push (to a collection):
firedux.push('users', { name: 'Jane' }, (id) => {
  // The ID is generated locally immediately,
  // so you can get it before the push with this callback.
  // id == '-K95Cjx-caw2uSNsFJiI'
})
.then((id) => {})
// state.firedux.data.users['-K95Cjx-caw2uSNsFJiI'] == { name: 'Jane' }

// Remove:
firedux.remove('users/joe')
.then(() => {})
// state.firedux.data.users['joe'] == undefined


// Auth
// WARNING: Auth methods may only support Firebase 2.x for now.

// Init
// Call this when your app starts, to get existing session, and listen for auth changes.
firedux.init()
// See Login state below.

// Login
firedux.login({
  email: 'user@example.com',
  password: '123'
})
// state.firedux.authData == { auth: { uid: '123' } }
//  etc. `authData` per https://www.firebase.com/docs/web/api/firebase/authwithcustomtoken.html
// or state.firedux.authError == Error

// Logout
firedux.logout()
// state.firedux.authData == null

// To handle some unsupported features, you can get access to the underlying Firebase instance via:
firedux.ref
// e.g. turn off a watch:
firedux.ref.child('users/joe').off('value')
// or login with OAuth:
firedux.ref.authWithOAuthPopup("twitter", (error, authData) => {
  store.dispatch({type: 'FIREBASE_LOGIN', error, authData})
})
```

## Running tests
{%= include("tests") %}

## Contributing
{%= include("contributing") %}
{%= include("contributing-extra") %}

## Author
{%= include("author") %}

## License
{%= copyright({start: 2015, linkify: true}) %}
{%= license({linkify: true}) %}

***

{%= include("footer") %}

[react]: https://facebook.github.io/react/
[redux]: http://redux.js.org/
[firebase]: https://www.firebase.com/
