EffectorJs 101

Why Bother?

Redux in a nutshell

State as tree

Means single root for entier app

...Or you need multiple stores and somehow link them together

State as graph?

State as graph?

import { a } from './state'

const value = useStore(a)

Application as graph of message streams?

Effects

Because events are boring

import { createEffect } from 'effector'

const loadPatient = createEffect({
  handler: (patientId: string) => http.get(`/patients/${patientId}`)
})

loadPatient.watch(() => console.log("Start loading"))
loadPatient.done.watch(() => console.log("Successfully loaded"))
loadPatient.fail.watch(() => console.log("Error"))
loadPatient.finally.watch(() => console.log("Operation completed"))

// or use as regular function
const patient = await loadPatient("123")

Stores

import { createStore } from 'effector'
import { loadPatient, Patient } from './patients'

export const patientIsLoading = createStore(false)
	.on(loadPatient, () => true)
	.reset(loadPatient.finally)

patientIsLoading
  .watch(value => console.log('Store value', value))

Dependent Stores

import { createStore } from 'effector'
import { loadPatient, Patient } from './patients'

// todo: complicated private store
// expose more primitive store with only data that is allowed to expose

Dependent Stores

import { createStore } from 'effector'
import { loadPatient, Patient } from './patients'

// todo: complicated private store
// expose more primitive store with only data that is allowed to expose

You can merge streams

import { merge } from 'effector'
import { participantLeft, participantJoined } from './participants'

const participanListChanged = merge([participantLeft, participantJoined])

participanListChanged.watch(() => console.log('participant list changed'))

You can split streams

import { split } from 'effector'
import { participantJoined } from './participants'

const byRole = split(participantJoined, {
  patient: ({role}) => role === 'patient',
  provider: ({role}) => role === 'provider'
})

byRole.patient.wathc(() => console.log('patient joined!'));

You can do weird stuff

import { split, createStore, createEffect, guard } from 'effector'
import { participantJoined } from './participants'

const byRole = split(participantJoined, {
  patient: ({role}) => role === 'patient',
  provider: ({role}) => role === 'provider'
})

const counter = createStore(0)
	.on(byRole.patient, (count) => count + 1)

const horray = createEffect()
	.use(() => {console.log("Patient joined 3 times!")})

guard({
  source: counter,
  filter: count => count % 3 === 0,
  target: horray,
})