forked from mobxjs/mobx
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcreate-transformer
More file actions
79 lines (59 loc) · 2.96 KB
/
Copy pathcreate-transformer
File metadata and controls
79 lines (59 loc) · 2.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# createTransformer
Mobservable supports transforming complete data graphs into other data graphs.
Derivations created using createTransformer are kept in sync with their source data automatically.
CreateTransformer effectively applies patches to the transformed graph if changes are made in the source graph.
This makes it very easy to achieve powerful patterns similar to like sideways data loading, map-reduce, tracking state history using immutable data structures etc...
// TODO api
Sounds fancy and vague, so let's dive into two examples of how you could apply this in practice:
## Example: substitute template values
Let's assume you have a huge text file in which you want variables to be substituted.
The substituted should always be in sync with both the file and the values of the variables to be substituted.
However, since the imaginary file is very large (or the substitution is expensive), you only want to update the lines that are actually affected by a change.
This is how you could apply `createTransformer` to achieve that:
```javascript
import {autorun, createTransformer, observable, map} from "mobservable";
class TextFile {
@observable text;
variables;
lineSubstitutor;
constructor(text, initialVariables) {
this.text = text;
this.variables = map(initialVariables);
// Reactively transforms a single line of text into substituted text
// e.g.:
this.lineSubstitutor = createTransformer(line => {
// Enable this line to see when lineSubstitutor is (not) called..!
// console.log("Substituting ", line);
return line.replace(/\$(\w+)/gi, (match, variableName) => {
return this.variables.get(variableName.toLowerCase());
});
});
autorun(() => {
const substituted = this.substitutedText;
console.log("New file contents: ", substituted);
}
}
@observable get textLines() {
return this.text.split("\n");
}
@observable get substitutedText() {
return this.textLines.map(this.lineSubstitutor).join("\n");
}
}
const textFile = new TextFile("Hello $USER,\n\nYou are $CHARACTERISTIC", {
user: "guest",
characteristic: "lovely"
});
// Prints: Hello guest, you are lovely
textFile.variables.set("characteristic", "awesome")
// Prints: Hello guest, you are awesome
textFile.text = "Hi, $CHARACTERISTIC $USER!";
// Prints: Hi, awesome guest!
```
`createTransformer(func)` creates turns a normal transformation function into one that will start observing all data it used during execution.
Similar to `observable(func)`.
But a transformer adds something special to the mix: it remembers that it has already been applied to an object before so that it will return the
result of an earlier transformation if possible. (And don't worry, garbage collection is arranged for as well).
So although `substitutedText` will always return a new map with all the substituted lines,
the `lineSubstitutor` will only perform actual work for lines that have changed or which will be affected by changed variables.
Try this example yourself in [jsfiddle](TODO)