Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ReanimatedCommitHook cloning #6776

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ RootShadowNode::Unshared ReanimatedCommitHook::shadowTreeWillCommit(
propsMap[&family].emplace_back(props);
});

rootNode = cloneShadowTreeWithNewProps(*rootNode, propsMap);
rootNode = cloneShadowTreeWithNewPropsUnmounted(rootNode, propsMap);

// If the commit comes from React Native then pause commits from
// Reanimated since the ShadowTree to be committed by Reanimated may not
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,36 @@
#ifdef RCT_NEW_ARCH_ENABLED

#include <react/renderer/core/DynamicPropsUtilities.h>
#include <reanimated/Fabric/ShadowTreeCloner.h>

#include <ranges>
#include <utility>

namespace reanimated {

ChildrenMap calculateChildrenMap(
const RootShadowNode &oldRootNode,
const PropsMap &propsMap) {
ChildrenMap childrenMap;

for (auto &[family, _] : propsMap) {
const auto ancestors = family->getAncestors(oldRootNode);

for (const auto &[parentNode, index] :
std::ranges::reverse_view(ancestors)) {
const auto parentFamily = &parentNode.get().getFamily();
auto &affectedChildren = childrenMap[parentFamily];

if (affectedChildren.contains(index)) {
continue;
}

affectedChildren.insert(index);
}
}
return childrenMap;
}

ShadowNode::Unshared cloneShadowTreeWithNewPropsRecursive(
const ShadowNode &shadowNode,
const ChildrenMap &childrenMap,
Expand Down Expand Up @@ -43,33 +67,87 @@ ShadowNode::Unshared cloneShadowTreeWithNewPropsRecursive(
return result;
}

RootShadowNode::Unshared cloneShadowTreeWithNewProps(
const RootShadowNode &oldRootNode,
ShadowNode::Unshared cloneShadowTreeWithNewPropsUnmountedRecursive(
ShadowNode::Shared const &oldShadowNode,
const ChildrenMap &childrenMap,
const PropsMap &propsMap) {
ChildrenMap childrenMap;
if (oldShadowNode->getHasBeenPromoted()) {
return cloneShadowTreeWithNewPropsRecursive(
*oldShadowNode, childrenMap, propsMap);
}

for (auto &[family, _] : propsMap) {
const auto ancestors = family->getAncestors(oldRootNode);
auto shadowNode = std::const_pointer_cast<ShadowNode>(oldShadowNode);

for (const auto &[parentNode, index] :
std::ranges::reverse_view(ancestors)) {
const auto parentFamily = &parentNode.get().getFamily();
auto &affectedChildren = childrenMap[parentFamily];
const auto family = &shadowNode->getFamily();
const auto affectedChildrenIt = childrenMap.find(family);
const auto propsIt = propsMap.find(family);
auto children = shadowNode->getChildren();

if (affectedChildren.contains(index)) {
continue;
if (affectedChildrenIt != childrenMap.end()) {
for (const auto index : affectedChildrenIt->second) {
auto clone = cloneShadowTreeWithNewPropsUnmountedRecursive(
children[index], childrenMap, propsMap);
if (clone != children[index]) {
shadowNode->replaceChild(*children[index], clone, index);
}
}
}

affectedChildren.insert(index);
Props::Shared newProps = nullptr;

if (propsIt != propsMap.end()) {
PropsParserContext propsParserContext{
shadowNode->getSurfaceId(), *shadowNode->getContextContainer()};
newProps = shadowNode->getProps();
for (const auto &props : propsIt->second) {
newProps = shadowNode->getComponentDescriptor().cloneProps(
propsParserContext, newProps, RawProps(props));
}
}

if (newProps) {
auto &props = shadowNode->getProps();
auto &mutableProps = const_cast<Props::Shared &>(props);

#ifdef ANDROID
auto &newPropsRef = const_cast<Props &>(*newProps);
newPropsRef.rawProps = mergeDynamicProps(
mutableProps->rawProps,
newProps->rawProps,
NullValueStrategy::Override);
#endif
mutableProps = newProps;
auto layoutableShadowNode =
static_pointer_cast<YogaLayoutableShadowNode>(shadowNode);
layoutableShadowNode->updateYogaProps();
}

return shadowNode;
}

RootShadowNode::Unshared cloneShadowTreeWithNewProps(
const RootShadowNode &oldRootNode,
const PropsMap &propsMap) {
auto childrenMap = calculateChildrenMap(oldRootNode, propsMap);

// This cast is safe, because this function returns a clone
// of the oldRootNode, which is an instance of RootShadowNode
return std::static_pointer_cast<RootShadowNode>(
cloneShadowTreeWithNewPropsRecursive(oldRootNode, childrenMap, propsMap));
}

RootShadowNode::Unshared cloneShadowTreeWithNewPropsUnmounted(
RootShadowNode::Unshared const &oldRootNode,
const PropsMap &propsMap) {
auto childrenMap = calculateChildrenMap(*oldRootNode, propsMap);

// This cast is safe, because this function returns a clone
// of the oldRootNode, which is an instance of RootShadowNode
return std::static_pointer_cast<RootShadowNode>(
cloneShadowTreeWithNewPropsUnmountedRecursive(
oldRootNode, childrenMap, propsMap));
}

} // namespace reanimated

#endif // RCT_NEW_ARCH_ENABLED
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ RootShadowNode::Unshared cloneShadowTreeWithNewProps(
const RootShadowNode &oldRootNode,
const PropsMap &propsMap);

RootShadowNode::Unshared cloneShadowTreeWithNewPropsUnmounted(
RootShadowNode::Unshared const &oldRootShadowNode,
const PropsMap &propsMap);

} // namespace reanimated

#endif // RCT_NEW_ARCH_ENABLED
Loading