UNPKG

2.76 kBJavaScriptView Raw
1import { observable, action, _allowStateChanges } from "mobx";
2/**
3 * `lazyObservable` creates an observable around a `fetch` method that will not be invoked
4 * until the observable is needed the first time.
5 * The fetch method receives a `sink` callback which can be used to replace the
6 * current value of the lazyObservable. It is allowed to call `sink` multiple times
7 * to keep the lazyObservable up to date with some external resource.
8 *
9 * Note that it is the `current()` call itself which is being tracked by MobX,
10 * so make sure that you don't dereference to early.
11 *
12 * @example
13 * const userProfile = lazyObservable(
14 * sink => fetch("/myprofile").then(profile => sink(profile))
15 * )
16 *
17 * // use the userProfile in a React component:
18 * const Profile = observer(({ userProfile }) =>
19 * userProfile.current() === undefined
20 * ? <div>Loading user profile...</div>
21 * : <div>{userProfile.current().displayName}</div>
22 * )
23 *
24 * // triggers refresh the userProfile
25 * userProfile.refresh()
26 *
27 * @param {(sink: (newValue: T) => void) => void} fetch method that will be called the first time the value of this observable is accessed. The provided sink can be used to produce a new value, synchronously or asynchronously
28 * @param {T} [initialValue=undefined] optional initialValue that will be returned from `current` as long as the `sink` has not been called at least once
29 * @returns {{
30 * current(): T,
31 * refresh(): T,
32 * reset(): T
33 * pending: boolean
34 * }}
35 */
36export function lazyObservable(fetch, initialValue) {
37 if (initialValue === void 0) { initialValue = undefined; }
38 var started = false;
39 var value = observable.box(initialValue, { deep: false });
40 var pending = observable.box(false);
41 var currentFnc = function () {
42 if (!started) {
43 started = true;
44 _allowStateChanges(true, function () {
45 pending.set(true);
46 });
47 fetch(function (newValue) {
48 _allowStateChanges(true, function () {
49 value.set(newValue);
50 pending.set(false);
51 });
52 });
53 }
54 return value.get();
55 };
56 var resetFnc = action("lazyObservable-reset", function () {
57 started = false;
58 value.set(initialValue);
59 return value.get();
60 });
61 return {
62 current: currentFnc,
63 refresh: function () {
64 if (started) {
65 started = false;
66 return currentFnc();
67 }
68 else {
69 return value.get();
70 }
71 },
72 reset: function () {
73 return resetFnc();
74 },
75 get pending() {
76 return pending.get();
77 },
78 };
79}