Skip to content

Commit ac46ab6

Browse files
author
Quan Nguyen
committed
Final fixes
1 parent f4d00f8 commit ac46ab6

File tree

13 files changed

+74
-495
lines changed

13 files changed

+74
-495
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
# 2.0.0
2+
- support immutable data structure
3+
- remove `didChange` and `getChanges`
4+
- remove `off('update')`
5+
- replace `on('update')` with `onUpdate`
6+
- replace `insertAt` and `removeAt` with `splice`
7+
- replace `add` with `merge`
8+
- swap `remove` and `destroy` method
9+
110
# 0.8.7
211
- fix multiple changes bug
312

README.md

Lines changed: 41 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
Cortex is a Javascript library for centrally managing data with React.
1+
Cortex is an immutable data store for managing deeply nested structure with React
22

33
**Key features:**
44
- supports deeply nested data
5-
- exposes changes for every data node
6-
- performs efficient batch updates and rewrapping
7-
- has built-in methods for working with arrays and hashes
5+
- uses immutable data structure for `shouldComponentUpdate` comparison
6+
- very efficient batch updates
7+
- simple APIs with built-in methods for working with arrays and hashes
8+
- very lightweight (4.5kB minified and gzip)
89
- written in ES6
910

1011
**Demos**
@@ -19,7 +20,8 @@ Initialize a cortex object
1920
var data = {a: 100, b: [1, 2, 3]};
2021

2122
var cortex = new Cortex(data, function(updatedCortex) {
22-
//trigger your React component to update props
23+
//trigger React component to update props
24+
myComponent.setProps({cortex: updatedCortex});
2325
});
2426
```
2527

@@ -56,46 +58,9 @@ cortex.getValue()
5658
// ==> {a: 300}
5759
```
5860

59-
Get the changes
60-
** Deprecated method. `getChanges` and `didChange` will be removed in cortex 2.0
61-
62-
```javascript
63-
cortex.getChanges(); // => [{type: "update", path: ['a'], oldValue: 200, newValue: 300}]
64-
65-
// changes are available at every node at any level. Note the difference in path
66-
cortex.a.getChanges(); // => [{type: "update", path: [], oldValue: 200, newValue: 300}]
67-
68-
// subtree without changes returns empty array
69-
cortex.b.getChanges(); // => []
70-
```
71-
72-
Alternatively you can also check whether a node changes
73-
```javascript
74-
cortex.didChange() // => true
75-
76-
cortex.didChange('a') // => true
77-
cortex.didChange('b') // => false
78-
79-
//same as above
80-
cortex.a.didChange() // => true
81-
cortex.b.didChange() // => false
82-
```
83-
84-
** You SHOULD NOT use `getChanges` and `didChange` to implement `shouldComponentUpdate` unless your components ONLY rely on cortex object to rerender. The reason is these changes are computed on cortex update and retained until the next update, so if your non-cortex props or state change then your nextProps, nextState would still contain the cortex changes of the previous cycle. This may incorrectly return true and results in your components updating more frequent than they should be.
85-
8661
Add callbacks
8762
```javascript
88-
cortex.on("update", myCallback);
89-
```
90-
91-
Remove callback
92-
```javascript
93-
cortex.off("update", myCallback);
94-
```
95-
96-
Remove all callbacks
97-
```javascript
98-
cortex.off("update");
63+
cortex.onUpdate(myCallback);
9964
```
10065

10166
### ES6 Guide
@@ -120,6 +85,25 @@ class MyComponent extends React.Component {
12085
}
12186
```
12287

88+
# Cortex 2.0 migration guide
89+
90+
The biggest change in v2 is immutable data. This allows us to implement `shouldComponentUpdate` as easy as
91+
92+
```javascript
93+
shouldComponentUpdate: function(nextProps, nextState) {
94+
return nextProps.myCortex !== this.props.myCortex;
95+
}
96+
```
97+
98+
Immutability also allows us to remove `getChanges` and `didChange` methods.
99+
100+
BREAKING CHANGES
101+
- `on('update', callback) is now simply onUpdate(callback)
102+
- `off('update', callback) is removed
103+
- `insertAt` and `removeAt` are replaced by `splice`, which behaves the same way as `Array.prototype.splice`
104+
- `add` is replaced by `merge`
105+
- for aesthetic reason, `remove` and `destroy` are swapped. So you would call `remove(key)` to remove a nested child and call `destroy` to remove self.
106+
123107
# Overview
124108

125109
In React's world data flows in one direction from the top down. That means if you want to make a change, change it at the source and let it propagate down the chain. But what happens when a child component needs to update the data? React's official guideline is to use callback for communication between parent and child components.
@@ -135,6 +119,9 @@ The following example has two components, Order and Item. An Order contains an a
135119

136120
```javascript
137121
var Item = React.createClass({
122+
shouldComponentUpdate: function(nextProps, nextState) {
123+
nextProps.item !== this.props.item;
124+
},
138125
increase: function() {
139126
var quantity = this.props.item.quantity.getValue();
140127
this.props.item.quantity.set(quantity + 1);
@@ -155,6 +142,9 @@ var Item = React.createClass({
155142
});
156143

157144
var Order = React.createClass({
145+
shouldComponentUpdate: function(nextProps, nextState) {
146+
147+
},
158148
render: function() {
159149
var items = this.props.order.map(function(item){
160150
return <Item item={item} />;
@@ -201,6 +191,8 @@ In Item component, note that we display the quantity value with ``this.props.ite
201191

202192
In `increase` method, we use ``this.props.item.quantity.set(quantity + 1)`` to add 1 to the current quantity value.
203193

194+
Note that we implement `shouldComponentUpdate` by simply comparing the current and next props. This comparison is extremely fast since cortex returns a brand new immutable wrapper when data change.
195+
204196
# Cortex API
205197

206198
### Initialize:
@@ -218,11 +210,8 @@ new Cortex(data, function() {
218210
`getValue()` | Returns the actual value
219211
`val()` | Alias for `getValue`
220212
`set(value)` | Changes the value and rewrap the subtree.
221-
`remove()` | Self destruct method: remove self from parent if nested, set value to undefined if root level.
222-
`on("update", callback)` | Add a callback to run on update event (only available on root object)
223-
`off("update", callback)`| Remove a callback. If no callback is specified, all existing callbacks will be removed (only available on root object)
224-
`getChanges()` | Returns array of changes. Each change include the change type (either 'new', 'update', or 'delete'), the path (array of keys to the changed subtree), oldValue, and newValue
225-
`didChange(key)` | Returns boolean value whether a change was made. key is an optional argument. When key provided, it checks whether changes occur in the key subtree. When not provided, it checks whether any change was made on the current node.
213+
`destroy()` | Self destruct method: remove self from parent if nested, set value to undefined if root level.
214+
`onUpdate(callback)` | Add a callback to run on update event (only available on root object)
226215

227216
### Cortex wrapper of array data has the following methods:
228217

@@ -238,8 +227,7 @@ new Cortex(data, function() {
238227
`pop()` | Removes the last element in the array
239228
`unshift(value)` | Inserts and rewrap the value at the front of the array.
240229
`shift()` | Removes the first element in the array
241-
`insertAt(index, [value])` | Inserts a value or an array of values starting at specified index.
242-
`removeAt(index, howMany = 1)` | Removes specified number of elements starting at index location. By default it removes 1 element if number of elements to be removed isn't specified.
230+
`splice(index, removeCount, element1 [, element2, ...])` | Remove `removeCount` from the array and insert elements into the array. This is similar to the native `Array.prototype.splice` method
243231

244232
### Cortex wrapper of hash data has the following methods:
245233
Methods | Description
@@ -248,17 +236,8 @@ new Cortex(data, function() {
248236
`values()` | Returns the array of values
249237
`hasKey(key)` | Returns boolean value whether the key exists
250238
`forEach(callback)` | Iterates over every key and value pair. The callback accepts the following inputs `(key, wrapperElement)`
251-
`destroy(key)` | Removes the specified key and value pair
252-
`add(key, value)` | Adds the specified key and value pair
253-
254-
255-
### Class methods
256-
257-
Methods | Description
258-
----------------------------------------------|:------------------
259-
`Cortex.deepDiff(oldValue, newValue)` | performs deep diff on 2 given objects
260-
`Cortex.deepClone(value)` | returns a deep copy of a given value
261-
239+
`remove(key)` | Removes the specified key and value pair
240+
`merge({key1: value1[, key2: value2, ...]})` | Adds/modifies the specified key and value pairs
262241

263242
# CDN
264243

@@ -315,7 +294,7 @@ Besides providing the convenience of allowing you to update data from any level,
315294

316295
### 1. Deep comparison between old and new values
317296

318-
When you issue a `set(newValue)` call, no data actually changes at that point. What happens internally is the wrapper being called publishes a notification to the master cortex wrapper passing along a payload consisting of the path for locating the data and the new value (Yes, there is a pub/sub system within Cortex.) The master wrapper then performs a deep comparison between the old and new data to determine whether it should trigger the update action. If no change was made, the process just exits without touching the data nor invoking the callbacks.
297+
When you issue a `set(newValue)` call, no data actually changes at that point. What happens internally is the wrapper being called publishes a notification to the master cortex wrapper passing along a payload consisting of the path for locating the data and the new value (Yes, there is a pub/sub system within Cortex.) The root wrapper then performs a deep comparison between the old and new data to determine whether it should trigger the update action. If no change was made, the process just terminates without touching the data nor invoking the callbacks.
319298

320299
Deep comparison may sound costly but in practice when you call `set(newValue)` the newValue usually isn't deeply nested (if it is and the actual change is many layers deep then you should consider calling `set(newValue)` on the wrapper at the level that the change actually occurs.) In some situations where you have to pass in arbirarily deeply nested value the comparison work is still worth it because it can potentially save you from unnecessarily rewrapping and triggering React to update.
321300

build/cortex.js

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -658,8 +658,13 @@ module.exports = (function () {
658658
}
659659

660660
_createClass(Cortex, [{
661-
key: "update",
662-
value: function update(diffs) {
661+
key: "onUpdate",
662+
value: function onUpdate(callback) {
663+
this.__callbacks.push(callback);
664+
}
665+
}, {
666+
key: "__update",
667+
value: function __update(diffs) {
663668
if (diffs.length) {
664669
if (!this.__updating) {
665670
this.__diffs = [];
@@ -682,17 +687,11 @@ module.exports = (function () {
682687
}
683688
}
684689
}
685-
}, {
686-
key: "onChange",
687-
value: function onChange(callback) {
688-
this.__callbacks.push(callback);
689-
}
690690
}, {
691691
key: "__subscribe",
692692
value: function __subscribe() {
693-
var self = this;
694693
this.__eventId = cortexPubSub.subscribeToCortex((function (topic, data) {
695-
this.update(data);
694+
this.__update(data);
696695
}).bind(this));
697696
}
698697
}, {

0 commit comments

Comments
 (0)