Skip to content

Commit

Permalink
Doc improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
mweststrate committed Aug 15, 2016
1 parent b1321ae commit 8940a7b
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 146 deletions.
300 changes: 162 additions & 138 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
# MobX-utils

Work in progress
_Utility functions and common patterns for MobX_

[![Build Status](https://travis-ci.org/mobxjs/mobx-utils.svg?branch=master)](https://travis-ci.org/mobxjs/mobx-utils)
[![Coverage Status](https://coveralls.io/repos/github/mobxjs/mobx-utils/badge.svg?branch=master)](https://coveralls.io/github/mobxjs/mobx-utils?branch=master)
[![Join the chat at https://gitter.im/mobxjs/mobx](https://badges.gitter.im/mobxjs/mobx.svg)](https://gitter.im/mobxjs/mobx?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

This package provides utility functions and common MobX patterns build on top of MobX.
It is encouraged to take a peek under the hood and read the sources of these utilities.
Feel free to open a PR with your own utilities. For large new features, please open an issue first.

# Installation

NPM: `npm install mobx-utils --save`
Expand All @@ -16,14 +20,15 @@ CDN: <https://npmcdn.com/mobx-utils/mobx-utils.umd.js>

## fromPromise

[lib/from-promise.js:78-82](https://github.com/mobxjs/mobx-utils/blob/91db1eb342f8af042320841b6c409a0f2d36fce5/lib/from-promise.js#L78-L82 "Source code on GitHub")
[lib/from-promise.js:78-82](https://github.com/mobxjs/mobx-utils/blob/b1321aea8c7aa934073a9973a73d867ce697bd04/lib/from-promise.js#L78-L82 "Source code on GitHub")

`fromPromise` takes a Promise and returns an object with 3 observable properties that track
the status of the promise. The returned object has the following observable properties:
`value`: either the initial value, or the value the Promise resolved to
`state`: one of `"pending"`, `"fulfilled"` or `"rejected"`
`reason`: the reject reason if the state is `"rejected"`
`promise`: (not observable) the original promise object

- `value`: either the initial value, or the value the Promise resolved to
- `state`: one of `"pending"`, `"fulfilled"` or `"rejected"`
- `reason`: the reject reason if the state is `"rejected"`
- `promise`: (not observable) the original promise object

**Parameters**

Expand Down Expand Up @@ -54,139 +59,24 @@ const myComponent = observer(({ fetchResult }) => {
})
```

Returns **IPromiseBasedObservable&lt;T>**

## whenWithTimeout

[lib/guarded-when.js:32-51](https://github.com/mobxjs/mobx-utils/blob/91db1eb342f8af042320841b6c409a0f2d36fce5/lib/guarded-when.js#L32-L51 "Source code on GitHub")

Like normal `when`, except that this `when` will automatically dispose if the condition isn't met within a certain amount of time.

**Parameters**

- `expr`
- `action`
- `timeout` **\[[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** maximum amount when spends waiting before giving up (optional, default `10000`)
- `onTimeout` **\[any]** the ontimeout handler will be called if the condition wasn't met withing the given time (optional, default `()`)

**Examples**

```javascript
test("expect store to load", t => {
const store = {
items: [],
loaded: false
}
fetchDataForStore((data) => {
store.items = data;
store.loaded = true;
})
whenWithTimeout(
() => store.loaded
() => t.end()
2000,
() => t.fail("expected store to load")
)
})
```

Returns **IDisposer** disposer function that can be used to cancel the when prematurely. Neither action or onTimeout will be fired if disposed

## keepAlive

[lib/keep-alive.js:35-40](https://github.com/mobxjs/mobx-utils/blob/91db1eb342f8af042320841b6c409a0f2d36fce5/lib/keep-alive.js#L35-L40 "Source code on GitHub")

MobX normally suspends any computed value that is not in use by any reaction,
and lazily re-evaluates the expression if needed outside a reaction while not in use.
`keepAlive` marks a computed value as always in use, meaning that it will always fresh, but never disposed.

**Parameters**

- `computedValue` **IComputedValue&lt;any>** created using the `computed` function
- `_1`
- `_2`

**Examples**

```javascript
const number = observable(3)
const doubler = computed(() => number.get() * 2)
const stop = keepAlive(doubler)
// doubler will now stay in sync reactively even when there are no further observers
stop()
// normal behavior, doubler results will be recomputed if not observed but needed, but lazily
```

Returns **IDisposer** stops this keep alive so that the computed value goes back to normal behavior

## keepAlive

[lib/keep-alive.js:35-40](https://github.com/mobxjs/mobx-utils/blob/91db1eb342f8af042320841b6c409a0f2d36fce5/lib/keep-alive.js#L35-L40 "Source code on GitHub")

MobX normally suspends any computed value that is not in use by any reaction,
and lazily re-evaluates the expression if needed outside a reaction while not in use.
`keepAlive` marks a computed value as always in use, meaning that it will always fresh, but never disposed.

**Parameters**

- `target` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** an object that has a computed property, created by `@computed` or `extendObservable`
- `property` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** the name of the property to keep alive
- `_1`
- `_2`

**Examples**

```javascript
const obj = observable({
number: 3,
doubler: function() { return this.number * 2 }
})
const stop = keepAlive(obj, "doubler")
```

Returns **IDisposer** stops this keep alive so that the computed value goes back to normal behavior

## queueProcessor

[lib/queue-processor.js:22-40](https://github.com/mobxjs/mobx-utils/blob/91db1eb342f8af042320841b6c409a0f2d36fce5/lib/queue-processor.js#L22-L40 "Source code on GitHub")

`queueProcessor` takes an observable array, observes it and calls `processor`
for each new item added to the observable array, optionally deboucing the action

**Parameters**

- `observableArray` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;T>** observable array instance to track
- `processor`
- `debounce` **\[[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** optional debounce time in ms. With debounce 0 the processor will run synchronously (optional, default `0`)

**Examples**

```javascript
const pendingNotifications = observable([])
const stop = queueProcessor(pendingNotifications, msg => {
// show Desktop notification
new Notification(msg);
})

// usage:
pendingNotifications.push("test!")
```

Returns **IDisposer** stops the processor
Returns **IPromiseBasedObservable&lt;T>**

## lazyObservable

[lib/lazy-observable.js:30-46](https://github.com/mobxjs/mobx-utils/blob/91db1eb342f8af042320841b6c409a0f2d36fce5/lib/lazy-observable.js#L30-L46 "Source code on GitHub")
[lib/lazy-observable.js:33-49](https://github.com/mobxjs/mobx-utils/blob/b1321aea8c7aa934073a9973a73d867ce697bd04/lib/lazy-observable.js#L33-L49 "Source code on GitHub")

creates an observable around a fetch method that will not be invoked
`lazyObservable` creates an observable around a `fetch` method that will not be invoked
util the observable is needed the first time.
The fetch method receives a sink callback which can be used to replace the
current value of the lazyObservable. It is allowed to call sink multiple times
The fetch method receives a `sink` callback which can be used to replace the
current value of the lazyObservable. It is allowed to call `sink` multiple times
to keep the lazyObservable up to date with some external resource.

Note that it is the `current()` call itself which is being tracked by MobX,
so make sure that you don't dereference to early.

**Parameters**

- `fetch`
- `fetch`
- `initialValue` **\[T]** optional initialValue that will be returned from `current` as long as the `sink` has not been called at least once (optional, default `undefined`)
- `modifier` **\[any]** optional mobx modifier that determines the the comparison and recursion strategy of the observable, for example `asFlat` or `asStructure` (optional, default `IDENTITY`)

Expand All @@ -207,7 +97,7 @@ const Profile = observer(({ userProfile }) =>

## fromResource

[lib/from-resource.js:63-97](https://github.com/mobxjs/mobx-utils/blob/91db1eb342f8af042320841b6c409a0f2d36fce5/lib/from-resource.js#L63-L97 "Source code on GitHub")
[lib/from-resource.js:65-99](https://github.com/mobxjs/mobx-utils/blob/b1321aea8c7aa934073a9973a73d867ce697bd04/lib/from-resource.js#L65-L99 "Source code on GitHub")

`fromResource` creates an observable which current state can be inspected using `.current()`,
and which can be kept in sync with some external datasource that can be subscribed to.
Expand All @@ -227,7 +117,7 @@ which comes from an imaginary database and notifies when it has changed.

**Parameters**

- `subscriber`
- `subscriber`
- `unsubscriber` **\[IDisposer]** (optional, default `NOOP`)
- `initialValue` **\[T]** the data that will be returned by `get()` until the `sink` has emitted its first data (optional, default `undefined`)

Expand All @@ -248,32 +138,34 @@ function createObservableUser(dbUserRecord) {
() => {
// the user observable is not in use at the moment, unsubscribe (for now)
dbUserRecord.unsubscribe(currentSubscription)
},
dbUserRecord.fields // optionally, provide initial data
}
)
}

// usage:
const myUserObservable = createObservableUser(myDatabaseConnector.query("name = 'Michel'"))

// use the observable in autorun
autorun(() => {
// printed everytime the database updates its records
console.log(myUserObservable.current().displayName)
})

// ... or a component
const userComponent = observer(({ user }) =>
<div>{user.get().displayName}</div>
<div>{user.current().displayName}</div>
)
```

## createViewModel

[lib/create-view-model.js:121-123](https://github.com/mobxjs/mobx-utils/blob/91db1eb342f8af042320841b6c409a0f2d36fce5/lib/create-view-model.js#L121-L123 "Source code on GitHub")
[lib/create-view-model.js:122-124](https://github.com/mobxjs/mobx-utils/blob/b1321aea8c7aa934073a9973a73d867ce697bd04/lib/create-view-model.js#L122-L124 "Source code on GitHub")

`createViewModel` takes an object with observable properties (model)
and wraps a view model around it. The view model proxies all enumerable property of the original model with the following behavior:

- as long as no new value has been assigned to the viewmodel property, the original property will be returned, and any future change in the model will be visible in the view model as well
- once a new value has been assigned to a property of the viewmodel, that value will be returned during a read of that property in the future
- once a new value has been assigned to a property of the viewmodel, that value will be returned during a read of that property in the future. However, the original model remain untouched until `submit()` is called.

The viewmodel exposes the following additional methods, besides all the enumerable properties of the model:

Expand All @@ -287,10 +179,142 @@ N.B. doesn't support observable arrays and maps yet

**Parameters**

- `model` **T**
- `model` **T**

**Examples**

```javascript
class Todo {
\@observable title = "Test"
}

const model = new Todo()
const viewModel = createViewModel(model);

autorun(() => console.log(viewModel.model.title, ",", viewModel.title))
// prints "Test, Test"
model.title = "Get coffee"
// prints "Get coffee, Get coffee", viewModel just proxies to model
viewModel.title = "Get tea"
// prints "Get coffee, Get tea", viewModel's title is now dirty, and the local value will be printed
viewModel.submit()
// prints "Get tea, Get tea", changes submitted from the viewModel to the model, viewModel is proxying again
viewModel.title = "Get cookie"
// prints "Get tea, Get cookie" // viewModel has diverged again
viewModel.reset()
// prints "Get tea, Get tea", changes of the viewModel have been abandoned
```

## whenWithTimeout

[lib/guarded-when.js:32-51](https://github.com/mobxjs/mobx-utils/blob/b1321aea8c7aa934073a9973a73d867ce697bd04/lib/guarded-when.js#L32-L51 "Source code on GitHub")

Like normal `when`, except that this `when` will automatically dispose if the condition isn't met within a certain amount of time.

**Parameters**

- `expr`
- `action`
- `timeout` **\[[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** maximum amount when spends waiting before giving up (optional, default `10000`)
- `onTimeout` **\[any]** the ontimeout handler will be called if the condition wasn't met within the given time (optional, default `()`)

**Examples**

```javascript
test("expect store to load", t => {
const store = {
items: [],
loaded: false
}
fetchDataForStore((data) => {
store.items = data;
store.loaded = true;
})
whenWithTimeout(
() => store.loaded
() => t.end()
2000,
() => t.fail("store didn't load with 2 secs")
)
})
```

Returns **IDisposer** disposer function that can be used to cancel the when prematurely. Neither action or onTimeout will be fired if disposed

## keepAlive

[lib/keep-alive.js:31-36](https://github.com/mobxjs/mobx-utils/blob/b1321aea8c7aa934073a9973a73d867ce697bd04/lib/keep-alive.js#L31-L36 "Source code on GitHub")

MobX normally suspends any computed value that is not in use by any reaction,
and lazily re-evaluates the expression if needed outside a reaction while not in use.
`keepAlive` marks a computed value as always in use, meaning that it will always fresh, but never disposed automatically.

**Parameters**

- `target` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** an object that has a computed property, created by `@computed` or `extendObservable`
- `property` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** the name of the property to keep alive
- `_1`
- `_2`

**Examples**

```javascript
const obj = observable({
number: 3,
doubler: function() { return this.number * 2 }
})
const stop = keepAlive(obj, "doubler")
```

Returns **IDisposer** stops this keep alive so that the computed value goes back to normal behavior

## keepAlive

[lib/keep-alive.js:31-36](https://github.com/mobxjs/mobx-utils/blob/b1321aea8c7aa934073a9973a73d867ce697bd04/lib/keep-alive.js#L31-L36 "Source code on GitHub")

**Parameters**

- `computedValue` **IComputedValue&lt;any>** created using the `computed` function
- `_1`
- `_2`

**Examples**

```javascript
const number = observable(3)
const doubler = computed(() => number.get() * 2)
const stop = keepAlive(doubler)
// doubler will now stay in sync reactively even when there are no further observers
stop()
// normal behavior, doubler results will be recomputed if not observed but needed, but lazily
```

Returns **IDisposer** stops this keep alive so that the computed value goes back to normal behavior

## queueProcessor

[lib/queue-processor.js:22-40](https://github.com/mobxjs/mobx-utils/blob/b1321aea8c7aa934073a9973a73d867ce697bd04/lib/queue-processor.js#L22-L40 "Source code on GitHub")

`queueProcessor` takes an observable array, observes it and calls `processor`
once for each item added to the observable array, optionally deboucing the action

**Parameters**

- `observableArray` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;T>** observable array instance to track
- `processor`
- `debounce` **\[[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** optional debounce time in ms. With debounce 0 the processor will run synchronously (optional, default `0`)

**Examples**

```javascript
const pendingNotifications = observable([])
const stop = queueProcessor(pendingNotifications, msg => {
// show Desktop notification
new Notification(msg);
})

// usage:
pendingNotifications.push("test!")
```

Returns **IDisposer** stops the processor

0 comments on commit 8940a7b

Please sign in to comment.