Skip to content

Commit

Permalink
introduce hierarchical mount
Browse files Browse the repository at this point in the history
Summary:
*This is a follow-up to D66176001*

## Recap
Signals constructs an isolated dependency graph for each mount item/render tree node in the mount phase due to the linear fashion in which mount works. This also means that there is no signal dependency between a render tree node and its children and that invalidations of descendant render tree nodes do not cause ancestors to remount. A major implication of this is that certain extensions such as the mount and render lifecycle extensions do not refire for ancestors of invalidated nodes.

This is quite different from what happens in the non-signals infra, in that, the reduced `BloksModel` hierarchy implicitly propagates dirtiness to the mount phase (via changed render units) such that ancestor nodes of an invalidated descendant re-mount.

The change in behavior from signals is much preferrable but it breaks expectations of products built in Bloks today. So we must align the signals mount behavior with that of the current infra within reason

## This Diff
Changes mount to happen in a recursive fashion such that dirtiness/invalidation can be propagated to an ancestor of an invalidated node. A dirty ancestor will go through the update phase just like in today's mount. However, the ancestor will still have the ability to skip its binders due to dependency tracking information and fine grained invalidation that signals provides.

NOTE: This change **still** maintains the isolated dependency graph behavior of each mount item as mount is not nested. So we still get the benefits of dirty checking shallow dependency graphs

Reviewed By: adityasharat

Differential Revision: D66541799

fbshipit-source-id: d530805a21f6507716e0f5a6e1c772714644c2f3
  • Loading branch information
Daniel Famakin authored and facebook-github-bot committed Nov 27, 2024
1 parent d0c6097 commit 51cf1a6
Showing 1 changed file with 18 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ constructor(
private val tracer: Systracer = RenderCoreSystrace.getInstance()
) : MountDelegateTarget {

private val idToMountedItemMap: LongSparseArray<MountItem?> = LongSparseArray()
protected val idToMountedItemMap: LongSparseArray<MountItem?> = LongSparseArray()
private val context: Context = _rootHost.context
private var isMounting = false
private var _needsRemount = false
Expand Down Expand Up @@ -143,15 +143,7 @@ constructor(

// Starting from 1 as the RenderTreeNode in position 0 always represents the root which
// is handled in prepareMount()
if (RenderCoreConfig.processFromLeafNode) {
for (i in (renderTree.mountableOutputCount - 1) downTo 1) {
updateMountItem(renderTree, i)
}
} else {
for (i in 1 until renderTree.mountableOutputCount) {
updateMountItem(renderTree, i)
}
}
mountItemsInternal(renderTree)

_needsRemount = false

Expand Down Expand Up @@ -198,6 +190,18 @@ constructor(
}
}

protected open fun mountItemsInternal(renderTree: RenderTree) {
if (RenderCoreConfig.processFromLeafNode) {
for (i in (renderTree.mountableOutputCount - 1) downTo 1) {
updateMountItem(renderTree, i)
}
} else {
for (i in 1 until renderTree.mountableOutputCount) {
updateMountItem(renderTree, i)
}
}
}

override fun unmountAllItems() {
try {
_rootHost.setInLayout()
Expand Down Expand Up @@ -347,10 +351,10 @@ constructor(
}
}

private fun isMountable(renderTreeNode: RenderTreeNode, index: Int): Boolean =
protected fun isMountable(renderTreeNode: RenderTreeNode, index: Int): Boolean =
_mountDelegate?.maybeLockForMount(renderTreeNode, index) ?: true

private fun updateBoundsForMountedRenderTreeNode(
protected fun updateBoundsForMountedRenderTreeNode(
renderTreeNode: RenderTreeNode,
item: MountItem,
mountDelegate: MountDelegate?
Expand Down Expand Up @@ -611,7 +615,7 @@ constructor(
}
}

private fun unmountItemRecursively(id: Long) {
protected fun unmountItemRecursively(id: Long) {
val item = idToMountedItemMap[id] ?: return // Already has been unmounted.

// When unmounting use the render unit from the MountItem
Expand Down Expand Up @@ -824,7 +828,7 @@ constructor(
unit.unmountBinders(context, content, node.layoutData, bindData, tracer)
}

private fun bindRenderUnitToContent(item: MountItem) {
protected fun bindRenderUnitToContent(item: MountItem) {
val renderUnit = item.renderUnit as RenderUnit<Any>
val content = item.content
val layoutData = item.renderTreeNode.layoutData
Expand Down

0 comments on commit 51cf1a6

Please sign in to comment.