Skip to main content

Observable API

observable#

observable<T>(targetIn: T, transaction? : Transaction) : T

observable returns a proxy for a state object that will:

  • Track references to properties when used useObservables.
  • React to property changes. Components that call useObservables are re-rendered when properties those components reference are mutated.
  • Performs tracking and reacting outside of React components using observe
  • Binds methods to the object, so they can be used without an object reference
  • Handles the memoization of any methods annotated as being memoized.
  • Extends this behaviour to referenced object by replacing them proxies.
ItemDescription
targetInAny object representing state
transactionAn optional transaction
returnsA proxy for the targetIn of the same type

observable is generally used outside of components at the start of the application to create long-lived observable objects that represent your store. Observable objects may also be created for shorter live objects, tied to a component using useLocalObservable

observer#

Wraps a component, making it an [observer] so it can react to any changes in referenced properties by rendering.

function observer<P>(Component : FunctionComponent<P>,          options? : ObserverOptions) : NamedExoticComponent<P>

See observe for a description of options though they are rarely needed.

As with other wrappers such as React.memo several syntax options are available.

function Value1 () { s    return (<div>{state.value1}</div>);}export default observer(Value1)

or for exporting named properties:

export const Value1 = observer(function Value1 () {     return (<div>{state.value1}</div>);});

finally this can be used but it won't preserve the name of the component for debugging:

export const Value1 = observer(() => {     return (<div>{state.value1}</div>);});

Tracks usage of any observable objects and re-renders the component when any of those properties are mutated. useObservables must only be used in a React functional component. For class based components use bindObservables. Outside of components use observe.

See observer for more details on the ObserverOptions. One relevant option, notifyParents can be set to true to force re-rendering even when children of tracked properties are mutated. Can be useful if you have child components that don't know about Proxily but still need to be re-rendered when data changes.

useObservableProp#

useObservableProp<S>(value: S) : [S, (value: S) => void]

Returns an array where the 1st element is a property value and the second a function used to set the property value. The property is the last one referenced. By passing a reference to a property in the argument this established the property in the argument as the last reference.

Used like this:

  const [value, setValue] = useObservableProp(counter.value)

Can only be used in a component wrapped as an observer.

setValue will be considered an action for tooling such as redux-devtools.

memoize#

Observable objects may have memoized getters or functions through memoize. A memoized function will only be recalculated when any of the state that it consumes changes or when the arguments change.

It can be used as a decorator proceeding a member function

@memoize()

or as a function that accepts a class or object, and it's member function name(s)

memoize (obj : any, propOrProps : string | Array<string>)

or as a function that accepts a class or an object plus a callback function that returns the property or method to be memoized:

memoize (obj: {new(...args: any[]): C} | C , cb :  (cls : C) => any)) 

memoize can only be used in functions that are properties of an observable object and cannot be used to make standalone functions memoized. There are other libraries suitable for standalone memoization.

nonObservable#

Sometimes you need for Proxily to leave certain properties alone and not create a proxy for them since they don't directly contain state and may function improperly if a proxy is created for them.

Two forms of nonObservable are allowed for this:

As a decorator proceeding a property

@nonObservable()

As a function that accepts a class or object, and it's property name(s)

nonObservable (obj : any, propOrProps : string | Array<string>)

As a function call to nominate either properties of an object or properties of a class as not being observable

ItemDescription
objAn object or a class
propsOrPropsAn array of property names or a single property name

In both cases the property will not be made observable. This is important when objects that don't directly represent state are included in an object that will be made observable.

useLocalObservable#

Creates an observable object tied to a component life-cycle

useLocalObservable<T>(callback : () => T, transaction? : Transaction) : T

Creates an observable object when the component mounts. Generally this is for shorter lived observable objects. The call back is only invoked once per component life-cycle and returns and object that will be made observable. Used like this:

const sampleListController = useLocalObservable(() => new ListController(sampleToDoList))

ObservableProvider#

A component that creates an observable object and places it in a context of your choice. Useful when iterating in JSX and requiring a new observable object on each iteration.

ObservableProvider = ({context, value, dependencies, transaction, children} : {    context : any,     value : Function | any,     dependencies : Array<any>,     transaction?: Transaction,     children: any})
OptionsDescription
contextA context created by React.createContext
valueA callback function that will return an object to be made observable or the object itself
dependenciesAn array of values that will be used to memoized the creation of a new object based when the values change
transactionAn optional transaction if the observable object is to be part of a transaction
childrenChild components are automatically passed in by using the component in JSX

Here is an example that creates a new observable object for each todoListItem:

<ObservableProvider key={index} context={ListItemContext} dependencies={[item]}                    value={() => new ListItemController(listController, item)}>    <ListItem key={index}/></ObservableProvider>

In the component you reference the observable like this

    const listItem = useContext(ListItemContext)

ListItemContext must be created with React.createContext

observe#

observe<T>(targetIn: T,             onChange : (target : string, prop : string) => void,              observer? : (target : T) => void,            observationOptions? : ObserveOptions)             : ObservationContext
interface ObserverOptionsAll {    batch: boolean,    delay: number | undefined,    notifyParents : boolean}

Used outside a component to observe state changes. For example, persist uses this internally to detect state changes and save them to local storage

ItemDescription
targetInAn observable object
onChangeA function that will be called when state in targetIn, or it's descendents change
observerA function that is called to reference any properties that are to be observed. If omitted all changes will be observed
observationOptionssee below
OptionDescription
batchdefaults to true so that updates are batched as described here. To disable batching set to false
delaydefaults to undefined which means that reactions are synchronous. Set to a time delay if you wish reactions to be debounced to a given time interval in milliseconds
notifyParentsdefaults to false meaning that if a state is mutated, only observers of that property will be notified. If set to true, observers of parents of the state are also notified as is the case for the immutable paradigm

groupUpdates#

Reactions to updates are normally batched such that they occur once per high-level function call. In async functions this is not the case and so you can force the reactions to be batched by placing them in a groupUpdates callback

groupUpdates = (callback : Function))

Example:

async doSomething () {    this.prop1 = 100;    await (new Promise((res : any) =>setTimeout(()=>res(), 1000)));    groupUpdates( () => {        this.prop2 = 200;        this.prop3 = 300;    })}