You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+30-28Lines changed: 30 additions & 28 deletions
Original file line number
Diff line number
Diff line change
@@ -83,16 +83,20 @@ let crystalizer = new Crystalizer({
83
83
84
84
## Samples
85
85
86
-
-**TODO** React TODO with undo/redo
87
-
-**TODO** Small backend with event-driven frontend
88
-
-**TODO**
86
+
Sample apps, as built, will be placed here and linked to `./samples`.
87
+
88
+
-**TODO** React TODO app with undo/redo
89
+
-**TODO** Time-based journal app
90
+
-**TODO** Thin backend with seamless offline experience
89
91
90
92
## What are 'Crystals' and 'Shards'? And why?
91
93
92
94
A crystalizer is, in essence, a reducer. With default settings, you get something that closely resembles state management from things like Redux. Which, of course, is just a normal reduce function used in a particular way. So, you might wonder what the names are for, and why not just use the colloquial names 'actions' and 'reducers'?
93
95
94
96
I'll answer that now, and also give an introduction to Crystalize.js.
95
97
98
+
## Introduction
99
+
96
100
Crystalize.js, while it _is_ essentially a reducer, it serves a different purpose. A reducer simply _reduces_ a collection of elements into a single aggregate. But, what Crystalize.js sets out to do is a little bit different. What if you want to keep the collection you passed in? What if you want variable amounts of that collection aggregated, or to be able to rewind to different points of that aggregation to see what it was at that point?
97
101
98
102
It's fair to consider think of a 'crystal' as an accumulator, and a 'shard' as an element. And that's really what they are. But that doesn't capture the goal of Crystalize.js, either.
@@ -101,8 +105,6 @@ They could likewise be called 'state' and 'actions', and that's really what they
101
105
102
106
Thus, the names are chosen to better reflect what Crystalize.js is doing, in verb form. Shards are _crystalized_ into an accumulated state, and the name calls that out to reflect the control and choice you have in how that process takes place.
103
107
104
-
## Introduction
105
-
106
108
To illustrate, here's the flow of an action+reducer:
107
109
108
110
```
@@ -115,7 +117,7 @@ To illustrate, here's the flow of an action+reducer:
115
117
readable
116
118
```
117
119
118
-
You pass actions into the reducer, and then they're aggregated into the accumulator, in this case, your action state. You have your state, which is great, but your action is gone. It cannot be replayed, and timing data about that action is lost, unless you add _additional_ state in order to track that information.
120
+
You pass actions into the reducer, and then they're aggregated into the accumulator, in this case, your app state. You have your state, which is great, but your action is gone. It cannot be replayed, and timing data about that action is lost, unless you add _additional state_ in order to track that information.
119
121
120
122
Here's the flow of Crystalize.js:
121
123
@@ -138,9 +140,9 @@ Here's the flow of Crystalize.js:
138
140
.take(N) .with(shards)
139
141
```
140
142
141
-
You add shards (colloquially, 'actions'), via the `with()` method. You get the state via the `take()` method. But, you can also do more than just get the final state. You also get `N` count of the most recent shards that were added via `with`, and the crystal that is the aggregate of the shards you did _not_ take.
143
+
You add shards (colloquially, 'actions'), via the `.with()` method. You get the state via the `take()` method. But, you can also do more than just get the final state. You also get `N` count of the most recent shards that were added via `.with`, and the crystal that is the aggregate of the shards you did _not_ take.
142
144
143
-
Putting this together, let's say you called `with()` and added 5 shards. Then, you called `.take(3)`. You'll get: 1) The final crystal, 2) The 3 most recently added shards, 3) The crystal that is the aggregate of the 2 oldest shards.
145
+
Putting this together, let's say you called `.with()` and added 5 shards. Then, you called `.take(3)`. You'll get: 1) The final crystal, 2) The 3 most recently added shards, 3) The crystal that is the aggregate of the 2 oldest shards.
The `.leave()` method is fine if you either know the historic index you want to backtrack to, or you simple want to increment the current one (undo/redo).
322
324
323
-
But, there might be time's where you want to focus on a specific shard and calculate both crystals as though that shard is the most recent shard.
325
+
But, there might be times where you want to focus on a specific shard and calculate both crystals as though that shard is the most recent shard.
Note that unlike `.leave()`, the internal pointer is _NOT_ reset when you call `.with()` or `.without()`. Instead, the pointer is updated for each call of `.with()` or `without()' per the seek function.
341
+
Note that unlike `.leave()`, the internal pointer is _NOT_ reset when you call `.with()` or `.without()`. Instead, the pointer is updated for each call of `.with()` or `.without()` per the seek function.
340
342
341
343
You can also use `.focus()` for a chronological value, such as `T` timestamp.
However, this relies on the shards being sorted by that value. We'll get into sorting as well in the next section, but there's also builtin ways to handle timestamps in Crystalize.js (see #TODO).
349
+
However, this relies on the shards being sorted by that value. We'll get into sorting as well in the next section, but there's also builtin ways to handle timestamps in Crystalize.js (see [Timestamp](#timestamp)).
348
350
349
351
## Init options
350
352
@@ -380,7 +382,7 @@ console.log(crystal);
380
382
// { total: 22 }
381
383
382
384
console.log(shards);
383
-
// Note that { timestamp: 3, value: 4 } is missing
385
+
// Note that { timestamp: 3, value: 3 } is missing
384
386
//
385
387
// [{ timestamp: 1, value: 2 },
386
388
// { timestamp: 1, value: 1 },
@@ -404,7 +406,7 @@ new Crystalizer<Crystal, Shard>({
404
406
405
407
### Map
406
408
407
-
You might wish to automatically add or change certain keys to every shard. Id`s are a great example of this. You can do so by specifying the `map` option, which takes a simple map function:
409
+
You might wish to automatically add or change certain keys to every shard. Id's are a great example of this. You can do so by specifying the `map` option, which takes a simple map function:
408
410
409
411
```typescript
410
412
import { ulid } from'ulid';
@@ -416,11 +418,11 @@ let crystalizer = new Crystalizer<Crystal, Shard>({
416
418
});
417
419
```
418
420
419
-
Now, all your shards will have a unique id from `ulid` if they didn't already have an id.
421
+
Now, all your shards will have a unique id from `ulid` if they didn't already have one.
420
422
421
423
### Timestamp
422
424
423
-
We have enough building blocks to ensure every shard has a timestamp, are ordered by those timestamps, and then revisit the `.focus()` example using them.
425
+
We have enough building blocks to ensure every shard has a timestamp, and are ordered by those timestamps.
424
426
425
427
```typescript
426
428
import { ulid } from'ulid';
@@ -436,7 +438,7 @@ let crystalizer = new Crystalizer<Crystal, Shard>({
436
438
});
437
439
```
438
440
439
-
We can do this much more simply by specifying the `tsKey` option:
441
+
But, we can do this much more simply by specifying the `tsKey` option:
0 commit comments