Skip to content

Commit

Permalink
Fix commit hook cloning
Browse files Browse the repository at this point in the history
  • Loading branch information
bartlomiejbloniarz committed Dec 2, 2024
1 parent 8eb8c3b commit 758d692
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 17 deletions.
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,34 @@
#ifdef RCT_NEW_ARCH_ENABLED

#include <reanimated/Fabric/ShadowTreeCloner.h>
#include <react/renderer/core/DynamicPropsUtilities.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,31 +65,79 @@ 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;

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 (oldShadowNode->getHasBeenPromoted()){
return cloneShadowTreeWithNewPropsRecursive(*oldShadowNode, childrenMap, propsMap);
}

auto shadowNode = std::const_pointer_cast<ShadowNode>(oldShadowNode);

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>(
cloneShadowTreeWithNewPropsRecursive(oldRootNode, childrenMap, propsMap));
return std::static_pointer_cast<RootShadowNode>(cloneShadowTreeWithNewPropsUnmountedRecursive(oldRootNode, childrenMap, propsMap));
}

} // namespace reanimated
Expand Down
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

0 comments on commit 758d692

Please sign in to comment.