Epics

Epic is a function that receives a stream of events and returns a stream of events. Although Stapp uses its mechanism to support epics, it has much in common with redux-observable and redux-most. We sincerely recommend following these links, if you are not familiar with the epics concept.

Epics allow harnessing async logic with ease.

Definition

type Epic<State> = (
  event$: Observable<Event<any, any>>,
  state$: Observable<State>,
  staticApi: {
    dispatch: Dispatch<State>
    getState(): State
  }
) => Subscribable<any> | void

Usage

Take the following as an example: search field with autosuggest.

import { createEffect, createEvent, createReducer } from 'stapp'
import { loaderStart, loaderEnd } from 'stapp-loaders'
import { debounceTime, mapTo, map, distinctUntilChanged, switchMap } from 'rxjs/operators'

const saveResults = createEvent('Save search results')

// EffectCreator returns an observable of three types of events:
// `start`, `success` or `fail` and `complete`.
const searchEffect = createEffect(
  // Effect description
  'Load suggestions',

  // Effect function, must return a value or a promise
  searchValue => fetch(`api?search=${searchValue}`).then(r => r.json())
)

const searchModule = {
  name: 'search',
  state: {
    search: createReducer([])
      .on(saveResults, (_, results) => results)
  },
  epic: [
    // Start loader on effect run
    searchEffect.start.epic(start$ => start$.pipe(
      mapTo(loaderStart('search'))
    )),

    // End loader on effect complete
    searchEffect.complete.epic(complete$ => complete$.pipe(
      mapTo(loaderEnd('search'))
    )),

    // Save results on success
    searchEffect.success.epic(success$ => success$.pipe(
      map(({ payload }) => saveResults(payload))
    )),

    // Search epic
    (_, state$) => state$.pipe(
      // track only one field changes
      map(state => state.values.search),

      // debounce and distinct value changes
      debounceTime(500),
      distinctUntilChanged(),

      // switch to effect function
      switchMap(({ payload: searchValue }) => searchEffect(searchValue))
    )
  ]
}

Epics allow reacting to events and state changes reactively. That's fun!

Filtering event stream by event type

select()

type select = (eventCreatorOrType:
  | AnyEventCreator
  | string
  | Array<AnyEventCreator | string>
) => (event: Event) => boolean
import { createEvent, select } from 'stapp'
import { filter } from 'rxjs/operators'

const myEventA = createEvent()
const myEventB = createEvent()

const epicA = (events$) => events$.pipe(
  filter(select(myEventA))
)

const epic = (events$) => events$.pipe(
  filter(select([myEventA, myEventB]))
)

createEpic

type createEpic = <Payload, Meta, State>(
  events: AnyEventCreator<Payload, Meta> | string | Array<AnyEventCreator | string>,
  fn: Epic<State>
) => Epic<State>

Accepts events and an Epic and returns a filtered Epic.

EventCreator.epic()

Accepts an Epic and returns an Epic, filtered by this EventCreator type.

const myEvent = createEvent()

const epic = myEvent.epic(myEvent$ => /* other stuff */)

results matching ""

    No results matching ""