0.1.0 • Published 6 years ago

fire-event-store-react v0.1.0

Weekly downloads
2
License
MIT
Repository
github
Last release
6 years ago

fire-event-store-react Travis npm package

This project is an experiment because I wanted to see if I could make a simple API for using Firestore as an event store in an event sourcing application.

The concepts/technology I am playing with here are:

  • Event Sourcing
  • Firebase / Firestore
  • CQRS / Message Bus (one component to write, another to read)
  • React context (using react-broadcast for now, until it changes!!)
  • HOC vs render props vs Function as Child Components

fire-event-store-react provides two Function as Child Components:

  1. <FireEventStore> does a few things:
  • Connects to Firebase and runs the documents at a given key through a reducer
  • Makes the resulting state from that reducer available to children
  • Puts a Firestore reference in context for <EventEmitter> components
  1. <EventEmitter> only does one thing:
  • Sends a new event to Firebase

Please note: As with anything that uses context, this library and react-broadcast which this library is based are both experimental. Either of these may cease working in some future version of React.

Installation

Using yarn:

$ yarn add fire-event-store-react

Then, use as you would anything else:

// using ES6 modules
import { FireEventStore, EventEmitter } from "fire-event-store-react"

// using CommonJS modules
var FireEventStore = require("fire-event-store-react").FireEventStore
var EventEmitter = require("fire-event-store-react").EventEmitter

The UMD build is also available on unpkg:

<script src="https://unpkg.com/fire-event-store-react/umd/fire-event-store-react.min.js"></script>

You can find the library on window.FireEventStoreReact. (Haven't actually tested this!)

Usage

The following is a totally contrived example, but illustrates the basic functionality we're after:

import React from "react"
import {
  initializeApp,
  FireEventStore,
  EventEmitter
} from "fire-event-store-react"

// Setup the Firebase app
initializeApp({
  apiKey: "...",
  authDomain: "...",
  databaseURL: "...",
  projectId: "...",
  storageBucket: "...",
  messagingSenderId: "..."
})

// Create a reducer
const initialState = { counter: 0 }
const reducer = (state = initialState, action) => {
  if (!action) return state
  switch (action.type) {
    case "INCREMENT":
      return { counter: state.counter + 1 }
    case "DECREMENT":
      return { counter: state.counter - 1 }
    default:
      return state
  }
}

// Use <FireEventStore /> around any component you want to be a container that
// is connected to the event stream, this could just be once at the top of the
// component tree and passed down via props
const App = props => (
  <FireEventStore
    stream="counter-events"                    // Any name for your event stream
    firebaseKey="counters/demo/counter-events" // Location of events in Firebase
    reducer={reducer}                          // The reducer from earlier
  >
    {state => (
      <div className="App">
        {/* Use the state as you normally would with this.state */}
        <div>{state.counter}</div>

        {/* Use the <EventEmitter /> component anywhere to emit a new event */}
        <EventEmitter stream="counter-events">
          {emit => (
            <div>
              <button
                className="button"
                onClick={() => emit({ type: "INCREMENT" })}
              >
                +
              </button>
              <button
                className="button"
                onClick={() => emit({ type: "DECREMENT" })}
              >
                -
              </button>
            </div>
          )}
        </EventEmitter>
      </div>
    )}
  </FireEventStore>
)

Enjoy!