mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Move ShadowNode::getAncestors to ShadowNodeFamily
Summary: Changelog: [internal] 1. Moves `ShadowNode::getAncestors` to `ShadowNodeFamily`. 2. Exposes shadowNode's family through `ShadowNode::getFamily()`. # Why? This is a first step in order to merge `StateCoordinator` into `ShadowNodeFamily` and use it as target for state updates. Reviewed By: shergin Differential Revision: D19465188 fbshipit-source-id: b5a3625aa21c040301259de02beedbf97e11f20e
This commit is contained in:
committed by
Facebook Github Bot
parent
8259a9d369
commit
01805636b9
@@ -47,10 +47,10 @@ RootShadowNode::Unshared RootShadowNode::clone(
|
||||
}
|
||||
|
||||
RootShadowNode::Unshared RootShadowNode::clone(
|
||||
ShadowNode const &shadowNode,
|
||||
ShadowNodeFamily const &shadowNodeFamily,
|
||||
std::function<ShadowNode::Unshared(ShadowNode const &oldShadowNode)>
|
||||
callback) const {
|
||||
auto ancestors = shadowNode.getAncestors(*this);
|
||||
auto ancestors = shadowNodeFamily.getAncestors(*this);
|
||||
|
||||
if (ancestors.size() == 0) {
|
||||
return RootShadowNode::Unshared{nullptr};
|
||||
@@ -59,7 +59,6 @@ RootShadowNode::Unshared RootShadowNode::clone(
|
||||
auto &parent = ancestors.back();
|
||||
auto &oldShadowNode = parent.first.get().getChildren().at(parent.second);
|
||||
|
||||
assert(ShadowNode::sameFamily(shadowNode, *oldShadowNode));
|
||||
auto newShadowNode = callback(*oldShadowNode);
|
||||
|
||||
auto childNode = newShadowNode;
|
||||
|
||||
@@ -55,7 +55,7 @@ class RootShadowNode final
|
||||
* Returns `nullptr` if the operation cannot be performed successfully.
|
||||
*/
|
||||
RootShadowNode::Unshared clone(
|
||||
ShadowNode const &shadowNode,
|
||||
ShadowNodeFamily const &shadowNodeFamily,
|
||||
std::function<ShadowNode::Unshared(ShadowNode const &oldShadowNode)>
|
||||
callback) const;
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <react/core/ShadowNodeFragment.h>
|
||||
#include <react/core/State.h>
|
||||
#include <react/core/StateCoordinator.h>
|
||||
#include <react/core/StateUpdate.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
@@ -99,7 +99,7 @@ LayoutMetrics LayoutableShadowNode::getRelativeLayoutMetrics(
|
||||
return layoutMetrics;
|
||||
}
|
||||
|
||||
auto ancestors = shadowNode.getAncestors(ancestorShadowNode);
|
||||
auto ancestors = shadowNode.getFamily().getAncestors(ancestorShadowNode);
|
||||
|
||||
if (ancestors.size() == 0) {
|
||||
return EmptyLayoutMetrics;
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
using AncestorList = ShadowNode::AncestorList;
|
||||
|
||||
SharedShadowNodeSharedList ShadowNode::emptySharedShadowNodeSharedList() {
|
||||
static const auto emptySharedShadowNodeSharedList =
|
||||
std::make_shared<SharedShadowNodeList>();
|
||||
@@ -215,44 +213,8 @@ void ShadowNode::setMounted(bool mounted) const {
|
||||
family_->eventEmitter_->setEnabled(mounted);
|
||||
}
|
||||
|
||||
AncestorList ShadowNode::getAncestors(
|
||||
ShadowNode const &ancestorShadowNode) const {
|
||||
auto families = better::small_vector<ShadowNodeFamily const *, 64>{};
|
||||
auto ancestorFamily = ancestorShadowNode.family_.get();
|
||||
|
||||
auto family = family_.get();
|
||||
while (family && family != ancestorFamily) {
|
||||
families.push_back(family);
|
||||
family = family->parent_.lock().get();
|
||||
}
|
||||
|
||||
if (family != ancestorFamily) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto ancestors = AncestorList{};
|
||||
auto parentNode = &ancestorShadowNode;
|
||||
for (auto it = families.rbegin(); it != families.rend(); it++) {
|
||||
auto childFamily = *it;
|
||||
auto found = false;
|
||||
auto childIndex = 0;
|
||||
for (const auto &childNode : *parentNode->children_) {
|
||||
if (childNode->family_.get() == childFamily) {
|
||||
ancestors.push_back({*parentNode, childIndex});
|
||||
parentNode = childNode.get();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
childIndex++;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
ancestors.clear();
|
||||
return ancestors;
|
||||
}
|
||||
}
|
||||
|
||||
return ancestors;
|
||||
ShadowNodeFamily const &ShadowNode::getFamily() const {
|
||||
return *family_;
|
||||
}
|
||||
|
||||
#pragma mark - DebugStringConvertible
|
||||
|
||||
@@ -28,7 +28,6 @@ static constexpr const int kShadowNodeChildrenSmallVectorSize = 8;
|
||||
|
||||
class ComponentDescriptor;
|
||||
struct ShadowNodeFragment;
|
||||
|
||||
class ShadowNode;
|
||||
|
||||
using SharedShadowNode = std::shared_ptr<const ShadowNode>;
|
||||
@@ -127,6 +126,8 @@ class ShadowNode : public virtual Sealable,
|
||||
|
||||
void sealRecursive() const;
|
||||
|
||||
ShadowNodeFamily const &getFamily() const;
|
||||
|
||||
#pragma mark - Mutating Methods
|
||||
|
||||
void appendChild(ShadowNode::Shared const &child);
|
||||
@@ -142,17 +143,6 @@ class ShadowNode : public virtual Sealable,
|
||||
*/
|
||||
void setMounted(bool mounted) const;
|
||||
|
||||
/*
|
||||
* Returns a list of all ancestors of the node relative to the given ancestor.
|
||||
* The list starts from the given ancestor node and ends with the parent node
|
||||
* of `this` node. The elements of the list have a reference to some parent
|
||||
* node and an index of the child of the parent node.
|
||||
* Returns an empty array if there is no ancestor-descendant relationship.
|
||||
* Can be called from any thread.
|
||||
* The theoretical complexity of the algorithm is `O(ln(n))`. Use it wisely.
|
||||
*/
|
||||
AncestorList getAncestors(ShadowNode const &ancestorShadowNode) const;
|
||||
|
||||
#pragma mark - DebugStringConvertible
|
||||
|
||||
#if RN_DEBUG_STRING_CONVERTIBLE
|
||||
@@ -175,6 +165,7 @@ class ShadowNode : public virtual Sealable,
|
||||
State::Shared state_;
|
||||
|
||||
private:
|
||||
friend ShadowNodeFamily;
|
||||
/*
|
||||
* Clones the list of children (and creates a new `shared_ptr` to it) if
|
||||
* `childrenAreShared_` flag is `true`.
|
||||
|
||||
@@ -6,12 +6,15 @@
|
||||
*/
|
||||
|
||||
#include "ShadowNodeFamily.h"
|
||||
#include "ShadowNode.h"
|
||||
|
||||
#include <react/core/ComponentDescriptor.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
using AncestorList = ShadowNode::AncestorList;
|
||||
|
||||
ShadowNodeFamily::ShadowNodeFamily(
|
||||
ShadowNodeFamilyFragment const &fragment,
|
||||
ComponentDescriptor const &componentDescriptor)
|
||||
@@ -40,5 +43,45 @@ ComponentName ShadowNodeFamily::getComponentName() const {
|
||||
return componentName_;
|
||||
}
|
||||
|
||||
AncestorList ShadowNodeFamily::getAncestors(
|
||||
ShadowNode const &ancestorShadowNode) const {
|
||||
auto families = better::small_vector<ShadowNodeFamily const *, 64>{};
|
||||
auto ancestorFamily = ancestorShadowNode.family_.get();
|
||||
|
||||
auto family = this;
|
||||
while (family && family != ancestorFamily) {
|
||||
families.push_back(family);
|
||||
family = family->parent_.lock().get();
|
||||
}
|
||||
|
||||
if (family != ancestorFamily) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto ancestors = AncestorList{};
|
||||
auto parentNode = &ancestorShadowNode;
|
||||
for (auto it = families.rbegin(); it != families.rend(); it++) {
|
||||
auto childFamily = *it;
|
||||
auto found = false;
|
||||
auto childIndex = 0;
|
||||
for (const auto &childNode : *parentNode->children_) {
|
||||
if (childNode->family_.get() == childFamily) {
|
||||
ancestors.push_back({*parentNode, childIndex});
|
||||
parentNode = childNode.get();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
childIndex++;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
ancestors.clear();
|
||||
return ancestors;
|
||||
}
|
||||
}
|
||||
|
||||
return ancestors;
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace facebook {
|
||||
namespace react {
|
||||
|
||||
class ComponentDescriptor;
|
||||
class ShadowNode;
|
||||
|
||||
/*
|
||||
* Represents all things that shadow nodes from the same family have in common.
|
||||
@@ -27,6 +28,12 @@ class ShadowNodeFamily {
|
||||
using Shared = std::shared_ptr<ShadowNodeFamily const>;
|
||||
using Weak = std::weak_ptr<ShadowNodeFamily const>;
|
||||
|
||||
using AncestorList = better::small_vector<
|
||||
std::pair<
|
||||
std::reference_wrapper<ShadowNode const> /* parentNode */,
|
||||
int /* childIndex */>,
|
||||
64>;
|
||||
|
||||
ShadowNodeFamily(
|
||||
ShadowNodeFamilyFragment const &fragment,
|
||||
ComponentDescriptor const &componentDescriptor);
|
||||
@@ -44,6 +51,17 @@ class ShadowNodeFamily {
|
||||
ComponentHandle getComponentHandle() const;
|
||||
ComponentName getComponentName() const;
|
||||
|
||||
/*
|
||||
* Returns a list of all ancestors of the node relative to the given ancestor.
|
||||
* The list starts from the given ancestor node and ends with the parent node
|
||||
* of `this` node. The elements of the list have a reference to some parent
|
||||
* node and an index of the child of the parent node.
|
||||
* Returns an empty array if there is no ancestor-descendant relationship.
|
||||
* Can be called from any thread.
|
||||
* The theoretical complexity of the algorithm is `O(ln(n))`. Use it wisely.
|
||||
*/
|
||||
AncestorList getAncestors(ShadowNode const &ancestorShadowNode) const;
|
||||
|
||||
private:
|
||||
friend ShadowNode;
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <react/core/ShadowNodeFragment.h>
|
||||
#include <react/core/State.h>
|
||||
#include <react/core/StateTarget.h>
|
||||
#include <react/core/StateUpdate.h>
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <folly/dynamic.h>
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include <exception>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "TestComponent.h"
|
||||
|
||||
using namespace facebook::react;
|
||||
|
||||
TEST(ShadowNodeFamilyTest, sealObjectCorrectly) {
|
||||
/*
|
||||
* The structure:
|
||||
* <A>
|
||||
* <AA>
|
||||
* <AAA/>
|
||||
* </AA>
|
||||
* </A>
|
||||
*/
|
||||
SurfaceId surfaceId = 1;
|
||||
auto eventDispatcher = std::shared_ptr<EventDispatcher const>();
|
||||
auto componentDescriptor = TestComponentDescriptor({eventDispatcher});
|
||||
auto props = std::make_shared<const TestProps>();
|
||||
|
||||
auto familyAAA = std::make_shared<ShadowNodeFamily>(
|
||||
ShadowNodeFamilyFragment{
|
||||
/* .tag = */ 12,
|
||||
/* .surfaceId = */ surfaceId,
|
||||
/* .eventEmitter = */ nullptr,
|
||||
},
|
||||
componentDescriptor);
|
||||
|
||||
auto nodeAAA = std::make_shared<TestShadowNode>(
|
||||
ShadowNodeFragment{
|
||||
/* .props = */ props,
|
||||
/* .children = */ ShadowNode::emptySharedShadowNodeSharedList(),
|
||||
},
|
||||
familyAAA,
|
||||
ShadowNodeTraits{});
|
||||
|
||||
auto nodeAAChildren =
|
||||
std::make_shared<SharedShadowNodeList>(SharedShadowNodeList{nodeAAA});
|
||||
auto familyAA = std::make_shared<ShadowNodeFamily>(
|
||||
ShadowNodeFamilyFragment{
|
||||
/* .tag = */ 11,
|
||||
/* .surfaceId = */ surfaceId,
|
||||
/* .eventEmitter = */ nullptr,
|
||||
},
|
||||
componentDescriptor);
|
||||
auto nodeAA = std::make_shared<TestShadowNode>(
|
||||
ShadowNodeFragment{
|
||||
/* .props = */ props,
|
||||
/* .children = */ nodeAAChildren,
|
||||
},
|
||||
familyAA,
|
||||
ShadowNodeTraits{});
|
||||
|
||||
auto nodeAChildren =
|
||||
std::make_shared<SharedShadowNodeList>(SharedShadowNodeList{nodeAA});
|
||||
|
||||
auto familyA = std::make_shared<ShadowNodeFamily>(
|
||||
ShadowNodeFamilyFragment{
|
||||
/* .tag = */ 17,
|
||||
/* .surfaceId = */ surfaceId,
|
||||
/* .eventEmitter = */ nullptr,
|
||||
},
|
||||
componentDescriptor);
|
||||
auto nodeA = std::make_shared<TestShadowNode>(
|
||||
ShadowNodeFragment{
|
||||
/* .props = */ props,
|
||||
/* .children = */ nodeAChildren,
|
||||
},
|
||||
familyA,
|
||||
ShadowNodeTraits{});
|
||||
|
||||
auto familyZ = std::make_shared<ShadowNodeFamily>(
|
||||
ShadowNodeFamilyFragment{
|
||||
/* .tag = */ 18,
|
||||
/* .surfaceId = */ surfaceId,
|
||||
/* .eventEmitter = */ nullptr,
|
||||
},
|
||||
componentDescriptor);
|
||||
auto nodeZ = std::make_shared<TestShadowNode>(
|
||||
ShadowNodeFragment{
|
||||
/* .props = */ props,
|
||||
/* .children = */ ShadowNode::emptySharedShadowNodeSharedList(),
|
||||
},
|
||||
familyZ,
|
||||
ShadowNodeTraits{});
|
||||
|
||||
// Negative case:
|
||||
auto ancestors1 = nodeZ->getFamily().getAncestors(*nodeA);
|
||||
EXPECT_EQ(ancestors1.size(), 0);
|
||||
|
||||
// Positive case:
|
||||
auto ancestors2 = nodeAAA->getFamily().getAncestors(*nodeA);
|
||||
EXPECT_EQ(ancestors2.size(), 2);
|
||||
EXPECT_EQ(&ancestors2[0].first.get(), nodeA.get());
|
||||
EXPECT_EQ(&ancestors2[1].first.get(), nodeAA.get());
|
||||
}
|
||||
@@ -222,18 +222,6 @@ TEST_F(ShadowNodeTest, handleCloneFunction) {
|
||||
EXPECT_EQ(nodeAB_->getProps(), nodeABClone->getProps());
|
||||
}
|
||||
|
||||
TEST_F(ShadowNodeTest, handleBacktracking) {
|
||||
// Negative case:
|
||||
auto ancestors1 = nodeZ_->getAncestors(*nodeA_);
|
||||
EXPECT_EQ(ancestors1.size(), 0);
|
||||
|
||||
// Positive case:
|
||||
auto ancestors2 = nodeABB_->getAncestors(*nodeA_);
|
||||
EXPECT_EQ(ancestors2.size(), 2);
|
||||
EXPECT_EQ(&ancestors2[0].first.get(), nodeA_.get());
|
||||
EXPECT_EQ(&ancestors2[1].first.get(), nodeAB_.get());
|
||||
}
|
||||
|
||||
TEST_F(ShadowNodeTest, handleState) {
|
||||
auto family = std::make_shared<ShadowNodeFamily>(
|
||||
ShadowNodeFamilyFragment{
|
||||
|
||||
@@ -153,7 +153,7 @@ void UIManager::setNativeProps(
|
||||
shadowTree.tryCommit(
|
||||
[&](RootShadowNode::Shared const &oldRootShadowNode) {
|
||||
return oldRootShadowNode->clone(
|
||||
shadowNode, [&](ShadowNode const &oldShadowNode) {
|
||||
shadowNode.getFamily(), [&](ShadowNode const &oldShadowNode) {
|
||||
return oldShadowNode.clone({
|
||||
/* .props = */ props,
|
||||
});
|
||||
@@ -200,7 +200,7 @@ void UIManager::updateState(
|
||||
shadowTree.tryCommit([&](RootShadowNode::Shared const
|
||||
&oldRootShadowNode) {
|
||||
return oldRootShadowNode->clone(
|
||||
shadowNode, [&](ShadowNode const &oldShadowNode) {
|
||||
shadowNode.getFamily(), [&](ShadowNode const &oldShadowNode) {
|
||||
auto &componentDescriptor =
|
||||
oldShadowNode.getComponentDescriptor();
|
||||
auto state = componentDescriptor.createState(
|
||||
|
||||
Reference in New Issue
Block a user