[WIP] Update ActionBar
to use support deep child trees using pure context
#6902
+156
−109
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Currently
ActionBar
only supports direct children because it usesChildren
APIs to find the props to determine what to render in the menu. By switching to a pure context-based approach using a registry that stores all the necessary data,ActionBar
can be updated to support deeply nested children, aliased children, fragments, etc.The children are registered with the same layout effect approach for determining their measurements, but they are now stored in a
Map
by unique ID rather than a simple array. The map allows them to update themselves if their props change and de-register themselves when they unmount.The challenge with this approach is preserving the order of the items in the registry vs in the React tree. We need the items in the registry to always be in the same order as the tree so that the
ActionBar
knows which ones are last (to hide first) and can preserve their order in the overflow menu. For this we rely onMap
preserving the insertion order. Since React will always render the tree from start to end, top to bottom, we know we'll receive the elements in the right order on the first render.However, effect cleanup still presents a challenge. If we don't clean up after ourselves, the
ActionBar
will never know if an item got removed from the bar. But if we remove items from the map on cleanup, they will get re-added at the end of the map when they update. So instead, I've set the values tonull
on cleanup and added logic to ignorenull
values in the component. This preserves the insertion order for the lifetime of the registry.Caveats: Unfortunately this approach is not perfect. While it's robust to an item getting removed from the list, or new items getting added to the end of the list, it will cause unexpected behavior if a new item is added in the middle or beginning of the list. This is because these items would be added at the end of the registry, rather than in the correct location. I haven't been able to come up with a solution for this -- we'd have to somehow trigger the registry to be rebuilt from scratch when an item is added, but I don't think that's possible without triggering infinite render loops, since items have to be added to build the registry in the first place.
TLDR: This change would allow consumers to wrap
ActionBar
item components, use aliased components, and otherwise provide indirect children. But the drawback is that it would cause unexpected behavior if new items are added to the beginning or middle after the initial render.FWIW, I think the drawback may be a reasonable tradeoff. I don't think that adding new items to the middle would be a very common scenario anyway.
Changelog
New
Changed
Removed
Rollout strategy
Testing & Reviewing
Merge checklist