ツリー構造に Immutable を使用する場合、そのノードへの内部参照を変更せずにノードを置き換えることは期待できないことに注意してください。つまり、そのような変更はツリーのルートまでバブルアップし、ルートも変更する必要があります。 .
詳細: メソッドを使用して特定のプロパティ値を変更するとすぐに、その特定のノードに対して新しいオブジェクトが返されます。次に、その新しいノードをツリー、つまり親の子リストに再注入するには、新しい子リストを作成するメソッドを使用します( childrenプロパティも不変であるため)。問題は、その子リストを親にアタッチすることです。これにより、新しい親ノードが作成されます...など。変更したいノードのすべての祖先ノードを再作成することになり、ルートからノードへのパスになかったノードを再利用する新しいツリー インスタンスが得られます。
画像を再利用するには、次のようになります。

Immutable API は、updateIn
メソッドを使用してこれを行うことができます (またはsetIn
、更新がターゲット ノードの 1 つのプロパティのみに関係する場合)。変更する (ネストされた) ノードを識別するために、キー パスを渡す必要があります。
たとえば、変更するノードの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);
}
children
ツリー、子を持つプロパティの名前 (この場合)、および探しているノードを識別する関数を渡す必要があります。ID 4 のノードへのパスが必要な場合は、次のように呼び出します。
var keyPath = findKeyPathOf(tree, 'children', node => node.get('id') == 4);
そのキー パスは次のようになります。配列内のインデックスの変更と、children
より深い配列を提供するプロパティです。
[0, 'children', 0, 'children', 1]
次に、そのパスのノードを変更するには、次のようにします。
var newTree = tree.updateIn(keyPath, node => node.set('name', 'Hello'));
以下は、いくつかのサンプル データを含むデモです。
// 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!');
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.min.js"></script>