Skip to content

Commit

Permalink
Fabric: Introducing ComponentDescriptorProvider
Browse files Browse the repository at this point in the history
Summary:
ComponentDescriptorProvider represents unified way to create a particular descriptor.
Now all ComponentViews (which support RCTComponentViewProtocol) expose a `ComponentDescriptorProvider` which will allow creating and registering ComponentDescriptor instances for all visual components automatically as a part of ComponentView registration process.
Don't panic, everything is still being as explicit as it always was, no magic involved; we just will have only one registration step instead of two parallel.

That also opens a way to register components on the fly.

Reviewed By: JoshuaGross

Differential Revision: D14963488

fbshipit-source-id: 9e9d9166fabaf7b30b35b8647faa6e3a19cd2435
  • Loading branch information
shergin authored and facebook-github-bot committed Apr 18, 2019
1 parent 0735873 commit 00eab3d
Show file tree
Hide file tree
Showing 18 changed files with 139 additions and 40 deletions.
Expand Up @@ -7,9 +7,9 @@

#import "RCTActivityIndicatorViewComponentView.h"

#import <react/components/rncore/ComponentDescriptors.h>
#import <react/components/rncore/EventEmitters.h>
#import <react/components/rncore/Props.h>
#import <react/components/rncore/ShadowNodes.h>

using namespace facebook::react;

Expand All @@ -29,9 +29,9 @@ @implementation RCTActivityIndicatorViewComponentView {

#pragma mark - RCTComponentViewProtocol

+ (ComponentHandle)componentHandle
+ (ComponentDescriptorProvider)componentDescriptorProvider
{
return ActivityIndicatorViewShadowNode::Handle();
return concreteComponentDescriptorProvider<ActivityIndicatorViewComponentDescriptor>();
}

- (instancetype)initWithFrame:(CGRect)frame
Expand Down
Expand Up @@ -8,10 +8,10 @@
#import "RCTImageComponentView.h"

#import <React/RCTImageResponseObserverProxy.h>
#import <react/components/image/ImageComponentDescriptor.h>
#import <react/components/image/ImageEventEmitter.h>
#import <react/components/image/ImageLocalData.h>
#import <react/components/image/ImageProps.h>
#import <react/components/image/ImageShadowNode.h>
#import <react/imagemanager/ImageRequest.h>
#import <react/imagemanager/RCTImagePrimitivesConversions.h>

Expand Down Expand Up @@ -46,9 +46,9 @@ - (instancetype)initWithFrame:(CGRect)frame

#pragma mark - RCTComponentViewProtocol

+ (ComponentHandle)componentHandle
+ (ComponentDescriptorProvider)componentDescriptorProvider
{
return ImageShadowNode::Handle();
return concreteComponentDescriptorProvider<ImageComponentDescriptor>();
}

- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps
Expand Down
Expand Up @@ -7,8 +7,8 @@

#import "RCTRootComponentView.h"

#import <react/components/root/RootComponentDescriptor.h>
#import <react/components/root/RootProps.h>
#import <react/components/root/RootShadowNode.h>

using namespace facebook::react;

Expand All @@ -24,9 +24,11 @@ - (instancetype)initWithFrame:(CGRect)frame
return self;
}

+ (ComponentHandle)componentHandle
#pragma mark - RCTComponentViewProtocol

+ (ComponentDescriptorProvider)componentDescriptorProvider
{
return RootShadowNode::Handle();
return concreteComponentDescriptorProvider<RootComponentDescriptor>();
}

@end
Expand Up @@ -8,10 +8,10 @@
#import "RCTScrollViewComponentView.h"

#import <React/RCTAssert.h>
#import <react/components/scrollview/ScrollViewComponentDescriptor.h>
#import <react/components/scrollview/ScrollViewEventEmitter.h>
#import <react/components/scrollview/ScrollViewLocalData.h>
#import <react/components/scrollview/ScrollViewProps.h>
#import <react/components/scrollview/ScrollViewShadowNode.h>
#import <react/graphics/Geometry.h>

#import "RCTConversions.h"
Expand Down Expand Up @@ -51,9 +51,9 @@ - (instancetype)initWithFrame:(CGRect)frame

#pragma mark - RCTComponentViewProtocol

+ (ComponentHandle)componentHandle
+ (ComponentDescriptorProvider)componentDescriptorProvider
{
return ScrollViewShadowNode::Handle();
return concreteComponentDescriptorProvider<ScrollViewComponentDescriptor>();
}

- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps
Expand Down
Expand Up @@ -10,8 +10,8 @@
#import <React/RCTImageResponseObserverProxy.h>
#import <react/components/rncore/EventEmitters.h>
#import <react/components/rncore/Props.h>
#import <react/components/slider/SliderComponentDescriptor.h>
#import <react/components/slider/SliderLocalData.h>
#import <react/components/slider/SliderShadowNode.h>

#import "MainQueueExecutor.h"

Expand Down Expand Up @@ -104,9 +104,9 @@ - (void)dealloc

#pragma mark - RCTComponentViewProtocol

+ (ComponentHandle)componentHandle
+ (ComponentDescriptorProvider)componentDescriptorProvider
{
return SliderShadowNode::Handle();
return concreteComponentDescriptorProvider<SliderComponentDescriptor>();
}

- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps
Expand Down
Expand Up @@ -7,9 +7,9 @@

#import "RCTSwitchComponentView.h"

#import <react/components/rncore/ComponentDescriptors.h>
#import <react/components/rncore/EventEmitters.h>
#import <react/components/rncore/Props.h>
#import <react/components/rncore/ShadowNodes.h>

using namespace facebook::react;

Expand Down Expand Up @@ -38,9 +38,9 @@ - (instancetype)initWithFrame:(CGRect)frame

#pragma mark - RCTComponentViewProtocol

+ (ComponentHandle)componentHandle
+ (ComponentDescriptorProvider)componentDescriptorProvider
{
return SwitchShadowNode::Handle();
return concreteComponentDescriptorProvider<SwitchComponentDescriptor>();
}

- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps
Expand Down
Expand Up @@ -7,9 +7,11 @@

#import "RCTParagraphComponentView.h"

#import <react/components/text/ParagraphComponentDescriptor.h>
#import <react/components/text/ParagraphLocalData.h>
#import <react/components/text/ParagraphProps.h>
#import <react/components/text/ParagraphShadowNode.h>
#import <react/components/text/RawTextComponentDescriptor.h>
#import <react/components/text/TextComponentDescriptor.h>
#import <react/core/LocalData.h>
#import <react/graphics/Geometry.h>
#import <react/textlayoutmanager/RCTTextLayoutManager.h>
Expand Down Expand Up @@ -40,9 +42,15 @@ - (instancetype)initWithFrame:(CGRect)frame

#pragma mark - RCTComponentViewProtocol

+ (ComponentHandle)componentHandle
+ (ComponentDescriptorProvider)componentDescriptorProvider
{
return ParagraphShadowNode::Handle();
return concreteComponentDescriptorProvider<ParagraphComponentDescriptor>();
}

+ (std::vector<facebook::react::ComponentDescriptorProvider>)supplementalComponentDescriptorProviders
{
return {concreteComponentDescriptorProvider<RawTextComponentDescriptor>(),
concreteComponentDescriptorProvider<TextComponentDescriptor>()};
}

- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps
Expand Down
Expand Up @@ -7,23 +7,16 @@

#import "RCTUnimplementedNativeComponentView.h"

#import <react/components/rncore/ComponentDescriptors.h>
#import <react/components/rncore/EventEmitters.h>
#import <react/components/rncore/Props.h>
#import <react/components/rncore/ShadowNodes.h>

using namespace facebook::react;

@implementation RCTUnimplementedNativeComponentView {
UILabel *_label;
}

#pragma mark - RCTComponentViewProtocol

+ (ComponentHandle)componentHandle
{
return UnimplementedNativeViewShadowNode::Handle();
}

- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
Expand All @@ -45,6 +38,13 @@ - (instancetype)initWithFrame:(CGRect)frame
return self;
}

#pragma mark - RCTComponentViewProtocol

+ (ComponentDescriptorProvider)componentDescriptorProvider
{
return concreteComponentDescriptorProvider<UnimplementedNativeViewComponentDescriptor>();
}

- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps
{
const auto &oldViewProps = *std::static_pointer_cast<const UnimplementedNativeViewProps>(oldProps ?: _props);
Expand Down
Expand Up @@ -10,9 +10,9 @@
#import <React/RCTAssert.h>
#import <React/RCTBorderDrawing.h>
#import <objc/runtime.h>
#import <react/components/view/ViewComponentDescriptor.h>
#import <react/components/view/ViewEventEmitter.h>
#import <react/components/view/ViewProps.h>
#import <react/components/view/ViewShadowNode.h>

#import "RCTConversions.h"

Expand Down Expand Up @@ -85,13 +85,13 @@ - (void)setBackgroundColor:(UIColor *)backgroundColor

#pragma mark - RCTComponentViewProtocol

+ (ComponentHandle)componentHandle
+ (ComponentDescriptorProvider)componentDescriptorProvider
{
RCTAssert(
self == [RCTViewComponentView class],
@"`+[RCTComponentViewProtocol componentHandle]` must be implemented for all subclasses (and `%@` particularly).",
@"`+[RCTComponentViewProtocol componentDescriptorProvider]` must be implemented for all subclasses (and `%@` particularly).",
NSStringFromClass([self class]));
return ViewShadowNode::Handle();
return concreteComponentDescriptorProvider<ViewComponentDescriptor>();
}

- (void)updateProps:(SharedProps)props oldProps:(SharedProps)oldProps
Expand Down
2 changes: 1 addition & 1 deletion React/Fabric/Mounting/RCTComponentViewFactory.mm
Expand Up @@ -49,7 +49,7 @@ - (void)registerComponentViewClass:(Class<RCTComponentViewProtocol>)componentVie
{
RCTAssertMainQueue();

ComponentHandle componentHandle = [componentViewClass componentHandle];
auto componentHandle = [componentViewClass componentDescriptorProvider].handle;
_registry[componentHandle] = componentViewClass;
}

Expand Down
11 changes: 9 additions & 2 deletions React/Fabric/Mounting/RCTComponentViewProtocol.h
Expand Up @@ -13,6 +13,7 @@
#import <react/core/LocalData.h>
#import <react/core/Props.h>
#import <react/core/State.h>
#import <react/uimanager/ComponentDescriptorProvider.h>

NS_ASSUME_NONNULL_BEGIN

Expand Down Expand Up @@ -40,10 +41,16 @@ typedef NS_OPTIONS(NSInteger, RNComponentViewUpdateMask) {
@protocol RCTComponentViewProtocol <NSObject>

/*
* Returns ComponentHandle of ComponentDescriptor which this ComponentView
* Returns a `ComponentDescriptorProvider` of a particular `ComponentDescriptor` which this component view
* represents.
*/
+ (facebook::react::ComponentHandle)componentHandle;
+ (facebook::react::ComponentDescriptorProvider)componentDescriptorProvider;

/*
* Returns a list of supplemental `ComponentDescriptorProvider`s (with do not have `ComponentView` counterparts) that
* require for this component view.
*/
+ (std::vector<facebook::react::ComponentDescriptorProvider>)supplementalComponentDescriptorProviders;

/*
* Called for mounting (attaching) a child component view inside `self`
Expand Down
6 changes: 3 additions & 3 deletions React/Fabric/Mounting/RCTComponentViewRegistry.mm
Expand Up @@ -106,9 +106,9 @@ - (void)preallocateViewComponents
// This data is based on empirical evidence which should represent the reality pretty well.
// Regular `<View>` has magnitude equals to `1` by definition.
std::vector<std::pair<ComponentHandle, float>> componentMagnitudes = {
{[RCTViewComponentView componentHandle], 1},
{[RCTImageComponentView componentHandle], 0.3},
{[RCTParagraphComponentView componentHandle], 0.3},
{[RCTViewComponentView componentDescriptorProvider].handle, 1},
{[RCTImageComponentView componentDescriptorProvider].handle, 0.3},
{[RCTParagraphComponentView componentDescriptorProvider].handle, 0.3},
};

// `complexity` represents the complexity of a typical surface in a number of `<View>` components (with Flattening
Expand Down
2 changes: 2 additions & 0 deletions React/Fabric/Mounting/UIView+ComponentViewProtocol.h
Expand Up @@ -16,6 +16,8 @@ NS_ASSUME_NONNULL_BEGIN
*/
@interface UIView (ComponentViewProtocol)

+ (std::vector<facebook::react::ComponentDescriptorProvider>)supplementalComponentDescriptorProviders;

- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index;

- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index;
Expand Down
5 changes: 5 additions & 0 deletions React/Fabric/Mounting/UIView+ComponentViewProtocol.mm
Expand Up @@ -17,6 +17,11 @@

@implementation UIView (ComponentViewProtocol)

+ (std::vector<facebook::react::ComponentDescriptorProvider>)supplementalComponentDescriptorProviders
{
return {};
}

- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
{
[self insertSubview:childComponentView atIndex:index];
Expand Down
2 changes: 1 addition & 1 deletion React/Fabric/RCTSurfacePresenter.mm
Expand Up @@ -175,7 +175,7 @@ - (BOOL)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictiona
if (componentView == nil) {
return NO; // This view probably isn't managed by Fabric
}
ComponentHandle handle = [[componentView class] componentHandle];
ComponentHandle handle = [[componentView class] componentDescriptorProvider].handle;
const facebook::react::ComponentDescriptor &componentDescriptor = [self._scheduler getComponentDescriptor:handle];
[self->_mountingManager synchronouslyUpdateViewOnUIThread:tag
changedProps:props
Expand Down
Expand Up @@ -30,6 +30,7 @@ using SharedComponentDescriptor = std::shared_ptr<ComponentDescriptor>;
class ComponentDescriptor {
public:
using Shared = std::shared_ptr<ComponentDescriptor const>;
using Unique = std::unique_ptr<ComponentDescriptor const>;

ComponentDescriptor(
EventDispatcher::Shared const &eventDispatcher,
Expand Down
69 changes: 69 additions & 0 deletions ReactCommon/fabric/uimanager/ComponentDescriptorProvider.h
@@ -0,0 +1,69 @@
/**
* 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.
*/

#pragma once

#include <react/core/ComponentDescriptor.h>
#include <react/core/EventDispatcher.h>
#include <react/utils/ContextContainer.h>

namespace facebook {
namespace react {

/*
* Callable signature that represents the signature of `ComponentDescriptor`
* constructor. The callable returns a unique pointer conveniently represents an
* abstract type and ownership of the newly created object.
*/
using ComponentDescriptorConstructor = ComponentDescriptor::Unique(
EventDispatcher::Shared const &eventDispatcher,
ContextContainer::Shared const &contextContainer);

/*
* Represents a unified way to construct an instance of a particular stored
* `ComponentDescriptor` class. C++ does not allow to create pointers to
* constructors, so we have to have such data structure to manipulate a
* collection of classes.
*/
class ComponentDescriptorProvider final {
public:
ComponentHandle handle;
ComponentDescriptorConstructor *constructor;
};

/*
* Creates a `ComponentDescriptorConstructor` for given `ComponentDescriptor`
* class.
*/
template <typename ComponentDescriptorT>
ComponentDescriptor::Unique concreteComponentDescriptorConstructor(
EventDispatcher::Shared const &eventDispatcher,
ContextContainer::Shared const &contextContainer) {
static_assert(
std::is_base_of<ComponentDescriptor, ComponentDescriptorT>::value,
"ComponentDescriptorT must be a descendant of ComponentDescriptor");

return std::make_unique<ComponentDescriptorT const>(
eventDispatcher, contextContainer);
}

/*
* Creates a `ComponentDescriptorProvider` for given `ComponentDescriptor`
* class.
*/
template <typename ComponentDescriptorT>
ComponentDescriptorProvider concreteComponentDescriptorProvider() {
static_assert(
std::is_base_of<ComponentDescriptor, ComponentDescriptorT>::value,
"ComponentDescriptorT must be a descendant of ComponentDescriptor");

return {ComponentDescriptorT::ConcreteShadowNode::Handle(),
&concreteComponentDescriptorConstructor<ComponentDescriptorT>};
}

} // namespace react
} // namespace facebook

0 comments on commit 00eab3d

Please sign in to comment.