Skip to content

Cado-Labs/observable

Repository files navigation

@cadolabs/observable · Supported by Cado Labs

Coverage Status Build Status

Install

$ yarn add @cadolabs/observable

Usage

The library contains of 4 parts - observable, observer, multipleObserver and useStore.

import { observable, observer, multipleObserver, useStore } from "@cadolabs/observable"

Structures

type InitialObject = Object
type State = Object
type Subscription = () => void
type ObserverFunction = Component => Observer<Component>

type ObservableStore = {
  set: (Object) => void, // set stored state (merge)
  observer: (ObserverOptions) => ObserverFunction // see observer
  getState: () => State, // returns current state
  subscribe: (Function) => Subscription, // subscribe on changes
  reset: () => void, // reset store to initial state
  ...InitialObject, // getters for the initial state keys
}

type ObserverOptions = {
  key: String, // property name
  map: (State => Object)? // function for mapping state
}

type MultipleObserverOptionItem = {
  store: ObservableStore, // store object
  key: String, // property name
  map: (State => Object)?, // function for mapping state
}

type UseStoreOptions = {
  map: (State => Object)?, // function for mapping state
}

observable

Creates observable store.

observable(initial: InitialObject): ObservableStore
import { observable } from "@cadolabs/observable"

const listStore = observable({ list: [] })

IMPORTANT: the store will have keys only from initial object

listStore.set({ otherKey: "value" })
listStore.otherKey // => undefined
listStore.set({ list: [1, 2,3] })
listStore.list // => [1, 2, 3]

observer

Subscribes React component on observable store.

observer(store: ObservableStore, options: ObserverOptions): ObserverFunction
import { observer } from "@cadolabs/observable"

@observer(listStore, {
  key: "categories",
  map: state => state.list
}) // or @listStore.observer({ key: "categories" })
class List extends React.Component {
  render () {
    const { categories } = this.props

    return <ul>{categories.map(item => <li key={item}>{item}</li>)}</ul>
  }
}

multipleObserver

Subscribes React component on multiple observable stores.

multipleObserver(stores: MultipleObserverOptionItem[]): ObserverFunction
import { multipleObserver } from "@cadolabs/observable"

@multipleObserver([
  { store: listStore, key: "categories", map: state => state.list },
  { store: userStore, key: "user" },
])
class List extends React.Component {
  render () {
    const { categories, user } = this.props

    return (
      <React.Fragment>
        <h2>{user.name}</h2>
        <ul>{categories.map(item => <li key={item}>{item}</li>)}</ul>
      </React.Fragment>
    )
  }
}

useStore

React hook that keeps track of the observable store.

useStore(store: ObservableStore, options: UseStoreOptions): State
import { useStore } from "@cadolabs/observable"

const List = () => {
  const categories = useStore(listStore, { map: state => state.list })

  return <ul>{categories.map(item => <li key={item}>{item}</li>)}</ul>
}

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/cadolabs/observable.

License

Released under MIT License.

Authors

Created by Aleksei Bespalov, inspired by idea of Aleksandr Komarov.

Supported by Cado Labs