1 | import { 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 | */
|
36 | export 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 | }
|