in packages/recoil/core/Recoil_Retention.js [76:139]
function findReleasableNodesInner(searchFromNodes: Set<NodeKey>): void {
const releasableNodesFoundThisIteration = new Set();
const downstreams = getDownstreamNodesInTopologicalOrder(
store,
treeState,
searchFromNodes,
releasableNodes, // don't descend into these
nonReleasableNodes, // don't descend into these
);
// Find which of the downstream nodes are releasable and which are not:
for (const node of downstreams) {
// Not releasable if configured to be retained forever:
if (getNode(node).retainedBy === 'recoilRoot') {
nonReleasableNodes.add(node);
continue;
}
// Not releasable if retained directly by a component:
if ((storeState.retention.referenceCounts.get(node) ?? 0) > 0) {
nonReleasableNodes.add(node);
continue;
}
// Not releasable if retained by a zone:
if (
zonesThatCouldRetainNode(node).some(z =>
storeState.retention.referenceCounts.get(z),
)
) {
nonReleasableNodes.add(node);
continue;
}
// Not releasable if it has a non-releasable child (which will already be in
// nonReleasableNodes because we are going in topological order):
const nodeChildren = graph.nodeToNodeSubscriptions.get(node);
if (
nodeChildren &&
someSet(nodeChildren, child => nonReleasableNodes.has(child))
) {
nonReleasableNodes.add(node);
continue;
}
releasableNodes.add(node);
releasableNodesFoundThisIteration.add(node);
}
// If we found any releasable nodes, we need to walk UP from those nodes to
// find whether their parents can now be released as well:
const parents = new Set();
for (const node of releasableNodesFoundThisIteration) {
for (const parent of graph.nodeDeps.get(node) ?? emptySet) {
if (!releasableNodes.has(parent)) {
parents.add(parent);
}
}
}
if (parents.size) {
findReleasableNodesInner(parents);
}
}