Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

state-tree

Package Overview
Dependencies
Maintainers
1
Versions
26
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

state-tree - npm Package Compare versions

Comparing version 0.1.6 to 0.1.7

tests/computed.js

2

package.json
{
"name": "state-tree",
"version": "0.1.6",
"version": "0.1.7",
"description": "A state tree that handles reference updates and lets you flush a description of changes",

@@ -5,0 +5,0 @@ "main": "src/index.js",

var React = require('react');
function hasPath(path, changes) {
function hasChanged(path, changes) {
return path.split('.').reduce(function (changes, key) {

@@ -22,3 +22,6 @@ return changes[key];

for (var key in paths) {
if (hasPath(paths[key], changes)) {
if (
(typeof paths[key] === 'object' && paths[key].hasChanged(changes)) ||
(hasChanged(paths[key], changes))
) {
return this.forceUpdate();

@@ -32,3 +35,3 @@ }

var propsToPass = Object.keys(paths || {}).reduce(function (props, key) {
props[key] = tree.get(paths[key]);
props[key] = typeof paths[key] === 'object' ? paths[key].get() : tree.get(paths[key]);
return props

@@ -35,0 +38,0 @@ }, {})

@@ -9,3 +9,3 @@ # state-tree (EXPERIMENTAL)

- **Control changes**. I want a simple way to track the changes made to the app. By using a `state.set('some.state', 'foo')` API instead of `some.state = 'foo'` this control becomes more intuitive as you have a specific API for making changes, rather than "changing stuff all over". It also makes it a lot easier to implement tracking of any changes
- **Control changes**. I want a simple way to control the changes made to the app. By using a `state.set('some.state', 'foo')` API instead of `some.state = 'foo'` this control becomes more intuitive as you have a specific API for making changes, rather than "changing stuff all over". It also makes it a lot easier to implement tracking of any changes

@@ -135,2 +135,3 @@ - **Fast updates**. Immutability has benefits like being able to replay state changes, undo/redo very easily and no unwanted mutations in other parts of your code. The problem though is that immutability is slow on instantiating large datasets

tree.set('foo', 'bar2');
tree.merge('foo', {something: 'cool'});
tree.unset('foo');

@@ -157,2 +158,4 @@ tree.push('list', 'something');

tree.set('list.0.foo', 'bar2');
// It returns an object representing the changes
tree.flushChanges(); // { list: { 0: { foo: true } } }

@@ -199,1 +202,60 @@ ```

```
### Computed
You can also compute state.
```js
import StateTree from 'state-tree';
const tree = StateTree({
foo: 'bar'
});
const myComputed = tree.computed({
foo: 'foo' // The deps, just like a component
}, state => {
return state.foo + '!!!';
});
myComputed.get() // "bar!!!"
let changes = tree.flushChanges(); // {}
myComputed.hasChanged(changes); // false
tree.set('foo', 'bar2');
changes = tree.flushChanges(); // { foo: true }
myComputed.hasChanged(changes); // true
myComputed.get() // "bar2!!!"
```
So, this seems like a lot of code to make computed work, but again, this is low level. Implemented in the HOC of React you can simply do this.
```js
import React from 'react';
import HOC from 'state-tree/react/HOC';
import addItem from './addItem';
import awesomeItems from './computed/awesomeItems';
function Items(props) {
return (
<div>
<button onClick={() => addItem({foo: 'bar'})}>Add item</button>
<ul>
{props.list.map((item, index) => <li key={index}>{item.foo}</li>)}
</ul>
</div>
);
}
export default HOC(Items, {
list: awesomeItems
})
```
And *awesomeItems.js* would look like:
```js
import tree from './tree';
export default tree.computed({
list: 'list' // Define its deps
}, state => {
return state.list.filter(item => item.isAwesome);
});
```
There is no magic going on here. The components will pass in the flushed "change tree" to whatever computed they have. This is what tells them to verify if an update is necessary, if not already ready to calculate a new value.

@@ -98,26 +98,32 @@ var subscribers = [];

module.exports = function (initialState) {
function StateTree(initialState) {
var state = setReferences(initialState, []);
var changes = {};
function updateChanges(host, key, specificPath) {
function update(pathArray) {
return function (currentPath, key, index) {
if (Array.isArray(key)) {
key = key[0].indexOf(key[1]);
currentPath[key] = index === pathArray.length - 1 ? true : {};
} else if (index === pathArray.length - 1 && !currentPath[key]) {
currentPath[key] = true;
} else if (index < pathArray.length - 1) {
currentPath[key] = typeof currentPath[key] === 'object' ? currentPath[key] : {};
function updateChanges(host, key, specificPath) {
function update(pathArray) {
return function (currentPath, key, index) {
if (Array.isArray(key)) {
key = key[0].indexOf(key[1]);
currentPath[key] = index === pathArray.length - 1 ? true : {};
} else if (index === pathArray.length - 1 && !currentPath[key]) {
currentPath[key] = true;
} else if (index < pathArray.length - 1) {
currentPath[key] = typeof currentPath[key] === 'object' ? currentPath[key] : {};
}
return currentPath[key];
}
return currentPath[key];
}
host['.referencePaths'].forEach(function (path) {
var pathArray = path ? path.concat(key) : [key];
pathArray.reduce(update(pathArray), changes);
});
}
host['.referencePaths'].forEach(function (path) {
var pathArray = path ? path.concat(key) : [key];
pathArray.reduce(update(pathArray), changes);
});
}
function hasChanged(path, changes) {
return path.split('.').reduce(function (changes, key) {
return changes[key];
}, changes);
}
return {

@@ -192,2 +198,22 @@ get: function (path) {

},
merge: function () {
var path;
var value;
if (arguments.length === 1) {
path = '';
value = arguments[0];
} else {
path = arguments[0];
value = arguments[1];
}
var pathArray = path.split('.');
var key = pathArray.pop();
var host = getByPath(pathArray, state);
var child = host[key] || host;
Object.keys(value).forEach(function (mergeKey) {
cleanReferences(child[mergeKey], state, key ? path.split('.').concat(mergeKey) : [mergeKey]);
child[mergeKey] = setReferences(value[mergeKey], key ? pathArray.concat(key, mergeKey) : [mergeKey]);
updateChanges(child, mergeKey, path);
});
},
subscribe: function (cb) {

@@ -206,4 +232,44 @@ subscribers.push(cb);

return flushedChanges;
},
computed: function (deps, cb) {
var computedHasChanged = true;
var value = null;
return {
get: function (changes) {
if (computedHasChanged) {
computedHasChanged = false;
value = cb(Object.keys(deps).reduce(function (props, key) {
var path = deps[key].split('.');
props[key] = getByPath(path, state);
return props;
}, {}));
return value;
} else {
return value;
}
},
// Can optimize by remembering the changes in case multiple
// components checks the computed, but very unlikely
hasChanged: function (changes) {
if (computedHasChanged) {
return true;
}
for (var key in deps) {
if (hasChanged(deps[key], changes)) {
computedHasChanged = true;
return true;
}
}
return false;
}
}
}
};
};
/*
- Create computed
- ComponentWillMount, subscribe to computed
*/
module.exports = StateTree;
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc