mirror of
https://github.com/status-im/react-native.git
synced 2025-02-21 13:48:13 +00:00
Fabric: Polishing RCTSurfacePresenter
Summary: Now RCTSurfacePresenter is uniquely responsible for: * Starting and stopping JS apps; * Restarting JS apps during hot-reload; * Recreating Scheduler during hot-reload. Reviewed By: mdvacca Differential Revision: D9931318 fbshipit-source-id: a6a3fb58814222f71cc6cb2caad620ed6319089d
This commit is contained in:
parent
24ffd8f6fb
commit
bce94dc8c3
@ -37,6 +37,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
- (void)registerSurface:(RCTFabricSurface *)surface;
|
||||
- (void)unregisterSurface:(RCTFabricSurface *)surface;
|
||||
- (void)setProps:(NSDictionary *)props
|
||||
surface:(RCTFabricSurface *)surface;
|
||||
|
||||
- (nullable RCTFabricSurface *)surfaceForRootTag:(ReactTag)rootTag;
|
||||
|
||||
/**
|
||||
@ -57,6 +60,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RCTSurfacePresenter (Deprecated)
|
||||
|
||||
@property (nonatomic) std::function<facebook::react::UIManagerInstaller> uiManagerInstaller;
|
||||
@property (nonatomic) std::function<facebook::react::UIManagerUninstaller> uiManagerUninstaller;
|
||||
|
||||
/**
|
||||
* We need to expose `uiManager` for registration
|
||||
* purposes. Eventually, we will move this down to C++ side.
|
||||
|
@ -38,11 +38,12 @@ using namespace facebook::react;
|
||||
@end
|
||||
|
||||
@implementation RCTSurfacePresenter {
|
||||
RCTScheduler *_scheduler;
|
||||
RCTScheduler *_Nullable _scheduler;
|
||||
RCTMountingManager *_mountingManager;
|
||||
RCTBridge *_bridge;
|
||||
RCTBridge *_batchedBridge;
|
||||
RCTSurfaceRegistry *_surfaceRegistry;
|
||||
SharedContextContainer _contextContainer;
|
||||
}
|
||||
|
||||
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
||||
@ -69,10 +70,10 @@ using namespace facebook::react;
|
||||
void *imageLoader = (__bridge void *)[[RCTBridge currentBridge] imageLoader];
|
||||
contextContainer->registerInstance(std::make_shared<ImageManager>(imageLoader));
|
||||
|
||||
_scheduler = [[RCTScheduler alloc] initWithContextContainer:contextContainer];
|
||||
_scheduler.delegate = self;
|
||||
_contextContainer = contextContainer;
|
||||
|
||||
_surfaceRegistry = [[RCTSurfaceRegistry alloc] init];
|
||||
|
||||
_mountingManager = [[RCTMountingManager alloc] init];
|
||||
_mountingManager.delegate = self;
|
||||
|
||||
@ -94,18 +95,19 @@ using namespace facebook::react;
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
#pragma mark - RCTSchedulerDelegate
|
||||
|
||||
- (void)schedulerDidFinishTransaction:(facebook::react::ShadowViewMutationList)mutations
|
||||
rootTag:(ReactTag)rootTag
|
||||
- (void)createSchedulerIfNeeded
|
||||
{
|
||||
[_mountingManager performTransactionWithMutations:mutations
|
||||
rootTag:rootTag];
|
||||
if (_scheduler) {
|
||||
return;
|
||||
}
|
||||
|
||||
_scheduler = [[RCTScheduler alloc] initWithContextContainer:_contextContainer];
|
||||
_scheduler.delegate = self;
|
||||
}
|
||||
|
||||
- (void)schedulerDidRequestPreliminaryViewAllocationWithComponentName:(NSString *)componentName
|
||||
- (void)ensureSchedulerDoesExist
|
||||
{
|
||||
[_mountingManager preliminaryCreateComponentViewWithName:componentName];
|
||||
RCTAssert(_scheduler, @"RCTSurfacePresenter: RCTScheduler instance must be already instantiated at this point.");
|
||||
}
|
||||
|
||||
#pragma mark - Internal Surface-dedicated Interface
|
||||
@ -113,20 +115,25 @@ using namespace facebook::react;
|
||||
- (void)registerSurface:(RCTFabricSurface *)surface
|
||||
{
|
||||
[_surfaceRegistry registerSurface:surface];
|
||||
[_scheduler registerRootTag:surface.rootTag];
|
||||
[self runSurface:surface];
|
||||
|
||||
// FIXME: mutation MUST produce instruction for root node.
|
||||
[_mountingManager.componentViewRegistry dequeueComponentViewWithName:@"Root" tag:surface.rootTag];
|
||||
[self startSurface:surface];
|
||||
}
|
||||
|
||||
- (void)unregisterSurface:(RCTFabricSurface *)surface
|
||||
{
|
||||
[self stopSurface:surface];
|
||||
[_scheduler unregisterRootTag:surface.rootTag];
|
||||
|
||||
[_surfaceRegistry unregisterSurface:surface];
|
||||
}
|
||||
|
||||
- (void)setProps:(NSDictionary *)props
|
||||
surface:(RCTFabricSurface *)surface
|
||||
{
|
||||
// This implementation is suboptimal indeed but still better than nothing for now.
|
||||
[self stopSurface:surface];
|
||||
[self startSurface:surface];
|
||||
}
|
||||
|
||||
- (RCTFabricSurface *)surfaceForRootTag:(ReactTag)rootTag
|
||||
{
|
||||
return [_surfaceRegistry surfaceForRootTag:rootTag];
|
||||
@ -136,6 +143,8 @@ using namespace facebook::react;
|
||||
maximumSize:(CGSize)maximumSize
|
||||
surface:(RCTFabricSurface *)surface
|
||||
{
|
||||
[self ensureSchedulerDoesExist];
|
||||
|
||||
LayoutContext layoutContext;
|
||||
layoutContext.pointScaleFactor = RCTScreenScale();
|
||||
LayoutConstraints layoutConstraints = {};
|
||||
@ -151,6 +160,8 @@ using namespace facebook::react;
|
||||
maximumSize:(CGSize)maximumSize
|
||||
surface:(RCTFabricSurface *)surface
|
||||
{
|
||||
[self ensureSchedulerDoesExist];
|
||||
|
||||
LayoutContext layoutContext;
|
||||
layoutContext.pointScaleFactor = RCTScreenScale();
|
||||
LayoutConstraints layoutConstraints = {};
|
||||
@ -162,53 +173,101 @@ using namespace facebook::react;
|
||||
rootTag:surface.rootTag];
|
||||
}
|
||||
|
||||
- (void)runSurface:(RCTFabricSurface *)surface
|
||||
- (void)startSurface:(RCTFabricSurface *)surface
|
||||
{
|
||||
[_mountingManager.componentViewRegistry dequeueComponentViewWithName:@"Root" tag:surface.rootTag];
|
||||
|
||||
[self createSchedulerIfNeeded];
|
||||
[_scheduler registerRootTag:surface.rootTag];
|
||||
|
||||
[self setMinimumSize:surface.minimumSize
|
||||
maximumSize:surface.maximumSize
|
||||
surface:surface];
|
||||
|
||||
// TODO: Move this down to Scheduler.
|
||||
NSDictionary *applicationParameters = @{
|
||||
@"rootTag": @(surface.rootTag),
|
||||
@"initialProps": surface.properties,
|
||||
};
|
||||
|
||||
[_batchedBridge enqueueJSCall:@"AppRegistry" method:@"runApplication" args:@[surface.moduleName, applicationParameters] completion:NULL];
|
||||
[self->_batchedBridge enqueueJSCall:@"AppRegistry" method:@"runApplication" args:@[surface.moduleName, applicationParameters] completion:NULL];
|
||||
}
|
||||
|
||||
- (void)stopSurface:(RCTFabricSurface *)surface
|
||||
{
|
||||
// TODO: Move this down to Scheduler.
|
||||
[_batchedBridge enqueueJSCall:@"ReactFabric" method:@"unmountComponentAtNode" args:@[@(surface.rootTag)] completion:NULL];
|
||||
|
||||
[self ensureSchedulerDoesExist];
|
||||
[_scheduler unregisterRootTag:surface.rootTag];
|
||||
|
||||
UIView<RCTComponentViewProtocol> *rootView = [_mountingManager.componentViewRegistry componentViewByTag:surface.rootTag];
|
||||
[_mountingManager.componentViewRegistry enqueueComponentViewWithName:@"Root" tag:surface.rootTag componentView:rootView];
|
||||
|
||||
[surface _unsetStage:(RCTSurfaceStagePrepared | RCTSurfaceStageMounted)];
|
||||
}
|
||||
|
||||
- (void)startAllSurfaces
|
||||
{
|
||||
for (RCTFabricSurface *surface in _surfaceRegistry.enumerator) {
|
||||
[self startSurface:surface];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stopAllSurfaces
|
||||
{
|
||||
for (RCTFabricSurface *surface in _surfaceRegistry.enumerator) {
|
||||
[self stopSurface:surface];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - RCTSchedulerDelegate
|
||||
|
||||
- (void)schedulerDidFinishTransaction:(facebook::react::ShadowViewMutationList)mutations
|
||||
rootTag:(ReactTag)rootTag
|
||||
{
|
||||
RCTFabricSurface *surface = [_surfaceRegistry surfaceForRootTag:rootTag];
|
||||
|
||||
[surface _setStage:RCTSurfaceStagePrepared];
|
||||
|
||||
[_mountingManager performTransactionWithMutations:mutations
|
||||
rootTag:rootTag];
|
||||
}
|
||||
|
||||
- (void)schedulerDidRequestPreliminaryViewAllocationWithComponentName:(NSString *)componentName
|
||||
{
|
||||
[_mountingManager preliminaryCreateComponentViewWithName:componentName];
|
||||
}
|
||||
|
||||
#pragma mark - RCTMountingManagerDelegate
|
||||
|
||||
- (void)mountingManager:(RCTMountingManager *)mountingManager willMountComponentsWithRootTag:(ReactTag)rootTag
|
||||
{
|
||||
RCTIsMainQueue();
|
||||
// TODO: Propagate state change to Surface.
|
||||
RCTAssertMainQueue();
|
||||
|
||||
// Does nothing.
|
||||
}
|
||||
|
||||
- (void)mountingManager:(RCTMountingManager *)mountingManager didMountComponentsWithRootTag:(ReactTag)rootTag
|
||||
{
|
||||
RCTIsMainQueue();
|
||||
RCTAssertMainQueue();
|
||||
|
||||
RCTFabricSurface *surface = [_surfaceRegistry surfaceForRootTag:rootTag];
|
||||
|
||||
// FIXME: Implement proper state propagation mechanism.
|
||||
[surface _setStage:RCTSurfaceStageSurfaceDidInitialRendering];
|
||||
[surface _setStage:RCTSurfaceStageSurfaceDidInitialLayout];
|
||||
[surface _setStage:RCTSurfaceStageSurfaceDidInitialMounting];
|
||||
|
||||
UIView *rootComponentView = [_mountingManager.componentViewRegistry componentViewByTag:rootTag];
|
||||
|
||||
surface.view.rootView = (RCTSurfaceRootView *)rootComponentView;
|
||||
RCTSurfaceStage stage = surface.stage;
|
||||
if (stage & RCTSurfaceStagePrepared) {
|
||||
// We have to progress the stage only if the preparing phase is done.
|
||||
if ([surface _setStage:RCTSurfaceStageMounted]) {
|
||||
UIView *rootComponentView = [_mountingManager.componentViewRegistry componentViewByTag:rootTag];
|
||||
surface.view.rootView = (RCTSurfaceRootView *)rootComponentView;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Bridge events
|
||||
|
||||
- (void)handleBridgeWillReloadNotification:(NSNotification *)notification
|
||||
{
|
||||
// TODO: Define a lifecycle contract for the pieces involved here including the scheduler, mounting manager, and
|
||||
// the surface registry. For now simply recreate the scheduler on reload.
|
||||
// The goal is to deallocate the Scheduler and its underlying references before the JS runtime is destroyed.
|
||||
_scheduler = [[RCTScheduler alloc] init];
|
||||
_scheduler.delegate = self;
|
||||
[self stopAllSurfaces];
|
||||
_scheduler = nil;
|
||||
}
|
||||
|
||||
- (void)handleJavaScriptDidLoadNotification:(NSNotification *)notification
|
||||
@ -216,6 +275,8 @@ using namespace facebook::react;
|
||||
RCTBridge *bridge = notification.userInfo[@"bridge"];
|
||||
if (bridge != _batchedBridge) {
|
||||
_batchedBridge = bridge;
|
||||
|
||||
[self startAllSurfaces];
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,6 +294,26 @@ using namespace facebook::react;
|
||||
return _bridge;
|
||||
}
|
||||
|
||||
- (void)setUiManagerInstaller:(std::function<facebook::react::UIManagerInstaller>)uiManagerInstaller
|
||||
{
|
||||
_contextContainer->registerInstance(uiManagerInstaller, "uimanager-installer");
|
||||
}
|
||||
|
||||
- (std::function<facebook::react::UIManagerInstaller>)uiManagerInstaller
|
||||
{
|
||||
return _contextContainer->getInstance<std::function<facebook::react::UIManagerInstaller>>("uimanager-installer");
|
||||
}
|
||||
|
||||
- (void)setUiManagerUninstaller:(std::function<facebook::react::UIManagerUninstaller>)uiManagerUninstaller
|
||||
{
|
||||
_contextContainer->registerInstance(uiManagerUninstaller, "uimanager-uninstaller");
|
||||
}
|
||||
|
||||
- (std::function<facebook::react::UIManagerUninstaller>)uiManagerUninstaller
|
||||
{
|
||||
return _contextContainer->getInstance<std::function<facebook::react::UIManagerUninstaller>>("uimanager-uninstaller");
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTBridge (RCTSurfacePresenter)
|
||||
|
@ -162,8 +162,7 @@
|
||||
_properties = [properties copy];
|
||||
}
|
||||
|
||||
// TODO: Implement this in RCTSurfacePresenter.
|
||||
// [_surfacePresenter setProps:properties surface:self];
|
||||
[_surfacePresenter setProps:properties surface:self];
|
||||
}
|
||||
|
||||
#pragma mark - Layout
|
||||
|
Loading…
x
Reference in New Issue
Block a user