Dis*_*ame 6 javascript immutability immutable.js immutable-collections
我有这样的树结构数据:
[{
id: 54,
name:123,
children: [{
id: 54,
name:123,
children: [{
id: 154,
name:1234,
children []...
}]
}]
}, {
...
}]
Run Code Online (Sandbox Code Playgroud)
我正在使用Angular 2.据我所知,无论何时输入发生变化,您的变化检测策略都会发生变化onPush.
为了优化树结构更新(例如,在嵌套级别切换节点或更改此类节点的任何属性),我使用了Immutable.
Immutable如何帮助我优化我的更新?我读到,当数据发生变化时,Immutable会重用旧数据中的引用来构造新对象.
如何有效地使用不可变数据结构来更新嵌套级别的节点?
keyPath任何节点.id属性值,可用于查询树数据(但是如何?)withMutationsAPI,但还有其他有效的方法吗?深层复制所有内容,然后修改新构造的对象:
var newState = deepClone(oldState) // deep copy everything and construct a new object
newState.nodes.forEach(node => {
if(node.id == 54) {
node.id = 789;
}
})
Run Code Online (Sandbox Code Playgroud)我想要实现的内容:
var newState = Immutable.fromJS(oldState) // create an immutable object
newState = newState.find(node => {
node.set("id", 123);
}); // any changes to object will return new object
Run Code Online (Sandbox Code Playgroud)使用第二个解决方案,我希望实现节点的重用,如下图所示:
意识到当你对树结构使用Immutable时,你不能指望在不改变对该节点的内部引用的情况下替换节点,这意味着这样的更改需要冒泡到树的根,也改变根.
更详细:只要使用方法更改某个属性值,就会获得为该特定节点返回的新对象.然后,要在树中重新注入该新节点,即在父项的子列表中,您将使用将创建新子列表的方法(因为children属性也是不可变的).现在的问题是将子列表附加到父节点,这将导致新的父节点,...等.您将最终重新创建要更改的节点的所有祖先节点,从而为您提供一个新的树实例,该实例将重用一些不在根节点路径中的节点.
要重新使用您的图片,您将获得以下内容:
Immutable API可以使用该updateIn方法为您执行此操作(或者setIn如果您的更新仅涉及目标节点的一个属性).您需要将密钥路径传递给它以标识要修改的(嵌套)节点.
因此,如果您知道要更改的节点的id,则可以使用一个小辅助函数来查找该特定节点的关键路径.
function findKeyPathOf(tree, childrenKey, predicate) {
var path;
if (Immutable.List.isList(tree)) {
tree.some(function (child, i) {
path = findKeyPathOf(child, childrenKey, predicate);
if (path) return path.unshift(i); // always returns truthy
});
return path;
}
if (predicate(tree)) return [];
path = findKeyPathOf(tree.get(childrenKey), childrenKey, predicate);
if (path) return [childrenKey].concat(path);
}
Run Code Online (Sandbox Code Playgroud)
您需要将树,具有子项的属性的名称(children在您的情况下)传递给它,以及将标识您要查找的节点的函数.假设您想要id为4的节点的路径,那么您可以像这样调用它:
var keyPath = findKeyPathOf(tree, 'children', node => node.get('id') == 4);
Run Code Online (Sandbox Code Playgroud)
该关键路径可能看起来像这样 - 更改数组中的索引,以及children提供更深层数组的属性:
[0, 'children', 0, 'children', 1]
Run Code Online (Sandbox Code Playgroud)
然后要修改该路径上的节点,您可以执行以下操作:
var newTree = tree.updateIn(keyPath, node => node.set('name', 'Hello'));
Run Code Online (Sandbox Code Playgroud)
这是一个包含一些示例数据的演示:
// Function to get the path to a certain node in the tree
function findKeyPathOf(tree, childrenKey, predicate) {
var path;
if (Immutable.List.isList(tree))
childrenKey = tree.findKey(child =>
path = findKeyPathOf(child, childrenKey, predicate));
else if (predicate(tree))
return [];
else
path = findKeyPathOf(tree.get(childrenKey), childrenKey, predicate);
return path && [childrenKey].concat(path);
}
// Function to compare two trees
function differences(tree1, tree2, childrenKey) {
if (Immutable.List.isList(tree1)) {
return tree1.reduce(function (diffs, child, i) {
return diffs.concat(differences(child, tree2.get(i), childrenKey));
}, []);
}
return (tree1 !== tree2 ? [tree1] : [])
.concat(differences(tree1.get(childrenKey), tree2.get(childrenKey),
childrenKey));
}
// Sample data
var tree = [{
id: 1,
name: 'Mike',
children: [{
id: 2,
name: 'Helen',
children: [{
id: 3,
name: 'John',
children: []
},{
id: 4,
name: 'Sarah',
children: [{
id: 5,
name: 'Joy',
children: []
}]
}]
}]
}, {
id: 6,
name: 'Jack',
children: [{
id: 7,
name: 'Irene',
children: []
},{
id: 8,
name: 'Peter',
children: []
}]
}];
// Create immutable tree from above plain object:
var tree = Immutable.fromJS(tree);
// Use the function to find the node with id == 4:
var keyPath = findKeyPathOf(tree, 'children', node => node.get('id') == 4);
// Found it?
if (keyPath) {
// Set 'name' to 'Hello' in that node:
var newTree = tree.updateIn(keyPath, node => node.set('name', 'Hello'));
// Print the new tree:
console.log(newTree.toJS());
// Compare all nodes to see which ones were altered:
var altered = differences(tree, newTree, 'children').map(x => x.get('id'));
console.log('IDs of nodes that were replaced: ', altered);
} else {
console.log('Not found!');
}Run Code Online (Sandbox Code Playgroud)
.as-console-wrapper { max-height: 100% !important; top: 0; }Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.min.js"></script>Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1195 次 |
| 最近记录: |