Run commit hooks before layout calculation (#36216)

Summary:
I've noticed that `UIManagerCommitHooks` are applied after calling `layoutIfNeeded`, meaning that if a commit hook makes some changes to the tree, it needs to calculate the layout again, effectively making the first calculation redundant.

This PR swaps the order of these two operations and moves `shadowTreeWillCommit` call before `layoutIfNeeded`. Thanks to this change, commit hooks don't need to manually trigger layout calculations as well as can potentially operate on unsealed nodes which can make it more efficient in some cases.

Finally, this PR eliminates a crash on `emitLayoutEvents(affectedLayoutableNodes);` when commit hook actually modifies the tree and thus de-allocates old shadow nodes.

cc sammy-SC

## Changelog

[GENERAL] [CHANGED] - Run commit hooks before layout calculation

Pull Request resolved: https://github.com/facebook/react-native/pull/36216

Test Plan: The only `UIManagerCommitHook` I could find in the OSS repo is [`TimelineController`](8bd3edec88/ReactCommon/react/renderer/timeline/TimelineController.h (L26)).

Reviewed By: cipolleschi

Differential Revision: D43569407

Pulled By: sammy-SC

fbshipit-source-id: 9ab1de0954cac2eb00346be7af8c9b3572bd2c88
This commit is contained in:
Tomek Zawadzki 2023-02-28 01:28:26 -08:00 коммит произвёл Facebook GitHub Bot
Родитель 987dd6a358
Коммит 8d0b5af1fc
1 изменённых файлов: 4 добавлений и 3 удалений

Просмотреть файл

@ -351,6 +351,10 @@ CommitStatus ShadowTree::tryCommit(
}
}
// Run commit hooks.
newRootShadowNode = delegate_.shadowTreeWillCommit(
*this, oldRootShadowNode, newRootShadowNode);
// Layout nodes.
std::vector<LayoutableShadowNode const *> affectedLayoutableNodes{};
affectedLayoutableNodes.reserve(1024);
@ -374,9 +378,6 @@ CommitStatus ShadowTree::tryCommit(
auto newRevisionNumber = oldRevision.number + 1;
newRootShadowNode = delegate_.shadowTreeWillCommit(
*this, oldRootShadowNode, newRootShadowNode);
if (!newRootShadowNode ||
(commitOptions.shouldYield && commitOptions.shouldYield())) {
return CommitStatus::Cancelled;