Merging Hierarchies
"What happens if I merge x into y?"
There are many different scenarios that we can run into when merging two hierarchy descriptors together via store.use(). This comprehensive guide will cover all of them.
The nodes
There are 4 types of hierarchy descriptors – the branch type and 3 types of leaves:
Branch - This is the branch node in the tree. It's just a plain object containing other nodes. See the Branch type documentation.
Reactor - A leaf node. See the Reactor type documentation.
Store - A leaf node. See the Store documentation.
null - A leaf node. Indicates a not-yet-created node or a node that should be removed.
The scenarios
We'll use the notation x -> y to mean "merge a node of type x into a node of type y."
Given our 4 node types, we have the following merge scenarios:
1. null -> null
2. null -> Branch
3. null -> Reactor
4. null -> Store
5. Branch -> null
6. Branch -> Branch
7. Branch -> Reactor
8. Branch -> Store
9. Reactor -> null
10. Reactor -> Branch
11. Reactor -> Reactor
12. Reactor -> Store
13. Store -> null
14. Store -> Branch
15. Store -> Reactor
16. Store -> Store
Any node in the hierarchy, including the root, may be any of these 4 types, and thus can encounter any of these 16 scenarios.
It may seem like a lot, but it's really pretty straightforward. Just remember the rules.
The rules
Type 6 (
Branch -> Branch) recursively merges the two nodes.Everything else always overwrites the given node (if it exists).
- The
null -> *scenarios remove the given node. - The
* -> nullscenarios create a node.
- The
See? Not so difficult.
Examples
import { createStore } from 'zedux'
const store = createStore()
// Reactor -> null
.use(aReactor) // creates the root node
// Reactor -> Reactor
.use(newReactor) // overwrites the root node
// Store -> Reactor
.use(aStore) // overwrites the root node
// Store -> Store
.use(anotherStore) // overwrites the root node
// Branch -> Store
.use({ // overwrites the root node
a: aReactor // creates a node
})
// Branch -> Branch
.use({ // is recursively merged into the root node
a: { // overwrites the "a" node
b: bStore // creates a node
},
c: cReactor // creates a node
})
// Branch -> Branch
.use({ // is recursively merged into the root node
// Reactor -> Branch
a: aReactor // overwrites the "a" node
// Branch -> Reactor
c: { // overwrites the "c" node
d: { // creates a node
e: eStore // creates a node
}
},
// Reactor -> null
f: fReactor // creates a node
})
// Branch -> Branch
.use({ // is recursively merged into the root node
// Branch -> Branch
c: { // is recursively merged into the "c" node
// Store -> Branch
d: dStore // overwrites the "c.d" node
},
// null -> Reactor
f: null // deletes the "f" node
})
Here's our hierarchy's final shape:
{
a: aReactor,
c: {
d: dStore
}
}
Notes
Don't get hierarchy descriptors and the resulting reactor hierarchy confused! Here we've been talking about hierarchy descriptors. Zedux will take the hierarchy descriptor passed to store.use(), merge it with the existing hierarchy descriptor (if any), then create a reactor hierarchy with that information.
Zedux builds the reactor hierarchy using a special, internally-created intermediate reactor for every Branch node found.
The data type returned by the intermediate reactors can be changed with the store.setNodeOptions() api. However, a plain object is always used in the hierarchy descriptor passed to store.use().