From 19ab84ffb7dd4fd28111343d8311df1a69f3a424 Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Thu, 27 Oct 2016 06:54:26 -0700 Subject: [PATCH] Cleanup and simplify view config generation Reviewed By: fkgozali Differential Revision: D4083308 fbshipit-source-id: 42ca797a8faede68bd031e84cf1c33a3e3ade37f --- .../ReactNative/requireNativeComponent.js | 50 ++++++----- React/Modules/RCTUIManager.m | 27 +++--- React/Views/RCTComponentData.m | 87 ++++++++----------- 3 files changed, 76 insertions(+), 88 deletions(-) diff --git a/Libraries/ReactNative/requireNativeComponent.js b/Libraries/ReactNative/requireNativeComponent.js index 8720d34cd3..d146b6c9dc 100644 --- a/Libraries/ReactNative/requireNativeComponent.js +++ b/Libraries/ReactNative/requireNativeComponent.js @@ -11,19 +11,19 @@ */ 'use strict'; -var ReactNativeStyleAttributes = require('ReactNativeStyleAttributes'); -var UIManager = require('UIManager'); -var UnimplementedView = require('UnimplementedView'); +const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes'); +const UIManager = require('UIManager'); +const UnimplementedView = require('UnimplementedView'); -var createReactNativeComponentClass = require('react/lib/createReactNativeComponentClass'); -var insetsDiffer = require('insetsDiffer'); -var matricesDiffer = require('matricesDiffer'); -var pointsDiffer = require('pointsDiffer'); -var processColor = require('processColor'); -var resolveAssetSource = require('resolveAssetSource'); -var sizesDiffer = require('sizesDiffer'); -var verifyPropTypes = require('verifyPropTypes'); -var warning = require('fbjs/lib/warning'); +const createReactNativeComponentClass = require('react/lib/createReactNativeComponentClass'); +const insetsDiffer = require('insetsDiffer'); +const matricesDiffer = require('matricesDiffer'); +const pointsDiffer = require('pointsDiffer'); +const processColor = require('processColor'); +const resolveAssetSource = require('resolveAssetSource'); +const sizesDiffer = require('sizesDiffer'); +const verifyPropTypes = require('verifyPropTypes'); +const warning = require('fbjs/lib/warning'); /** * Used to create React components that directly wrap native component @@ -47,29 +47,34 @@ function requireNativeComponent( componentInterface?: ?ComponentInterface, extraConfig?: ?{nativeOnly?: Object}, ): Function { - var viewConfig = UIManager[viewName]; + const viewConfig = UIManager[viewName]; if (!viewConfig || !viewConfig.NativeProps) { warning(false, 'Native component for "%s" does not exist', viewName); return UnimplementedView; } - var nativeProps = { - ...UIManager.RCTView.NativeProps, - ...viewConfig.NativeProps, - }; + viewConfig.uiViewClassName = viewName; viewConfig.validAttributes = {}; viewConfig.propTypes = componentInterface && componentInterface.propTypes; - for (var key in nativeProps) { - var useAttribute = false; - var attribute = {}; - var differ = TypeToDifferMap[nativeProps[key]]; + // The ViewConfig doesn't contain any props inherited from the view manager's + // superclass, so we manually merge in the RCTView ones. Other inheritance + // patterns are currenty not supported. + const nativeProps = { + ...UIManager.RCTView.NativeProps, + ...viewConfig.NativeProps, + }; + for (const key in nativeProps) { + let useAttribute = false; + const attribute = {}; + + const differ = TypeToDifferMap[nativeProps[key]]; if (differ) { attribute.diff = differ; useAttribute = true; } - var processor = TypeToProcessorMap[nativeProps[key]]; + const processor = TypeToProcessorMap[nativeProps[key]]; if (processor) { attribute.process = processor; useAttribute = true; @@ -92,6 +97,7 @@ function requireNativeComponent( extraConfig && extraConfig.nativeOnly ); } + return createReactNativeComponentClass(viewConfig); } diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index b1be517326..2db1bc9419 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -1472,22 +1472,19 @@ RCT_EXPORT_METHOD(clearJSResponder) - (NSDictionary *)constantsToExport { - NSMutableDictionary *allJSConstants = [NSMutableDictionary new]; + NSMutableDictionary *constants = [NSMutableDictionary new]; NSMutableDictionary *directEvents = [NSMutableDictionary new]; NSMutableDictionary *bubblingEvents = [NSMutableDictionary new]; - [_componentDataByName enumerateKeysAndObjectsUsingBlock: - ^(NSString *name, RCTComponentData *componentData, __unused BOOL *stop) { - - NSMutableDictionary *constantsNamespace = - [NSMutableDictionary dictionaryWithDictionary:allJSConstants[name]]; + [_componentDataByName enumerateKeysAndObjectsUsingBlock:^(NSString *name, RCTComponentData *componentData, __unused BOOL *stop) { + NSMutableDictionary *moduleConstants = [NSMutableDictionary new]; // Add manager class - constantsNamespace[@"Manager"] = RCTBridgeModuleNameForClass(componentData.managerClass); + moduleConstants[@"Manager"] = RCTBridgeModuleNameForClass(componentData.managerClass); // Add native props NSDictionary *viewConfig = [componentData viewConfig]; - constantsNamespace[@"NativeProps"] = viewConfig[@"propTypes"]; + moduleConstants[@"NativeProps"] = viewConfig[@"propTypes"]; // Add direct events for (NSString *eventName in viewConfig[@"directEvents"]) { @@ -1519,19 +1516,19 @@ RCT_EXPORT_METHOD(clearJSResponder) } } - allJSConstants[name] = constantsNamespace; + RCTAssert(!constants[name], @"UIManager already has constants for %@", componentData.name); + constants[name] = moduleConstants; }]; #if !TARGET_OS_TV _currentInterfaceOrientation = [RCTSharedApplication() statusBarOrientation]; #endif - [allJSConstants addEntriesFromDictionary:@{ - @"customBubblingEventTypes": bubblingEvents, - @"customDirectEventTypes": directEvents, - @"Dimensions": RCTExportedDimensions(NO) - }]; - return allJSConstants; + constants[@"customBubblingEventTypes"] = bubblingEvents; + constants[@"customDirectEventTypes"] = directEvents; + constants[@"Dimensions"] = RCTExportedDimensions(NO); + + return constants; } static NSDictionary *RCTExportedDimensions(BOOL rotateBounds) diff --git a/React/Views/RCTComponentData.m b/React/Views/RCTComponentData.m index e9adeb0112..0b9d8414cc 100644 --- a/React/Views/RCTComponentData.m +++ b/React/Views/RCTComponentData.m @@ -400,83 +400,68 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) NSMutableArray *directEvents = [NSMutableArray new]; if (RCTClassOverridesInstanceMethod(_managerClass, @selector(customDirectEventTypes))) { NSArray *events = [self.manager customDirectEventTypes]; -#pragma clang diagnostic pop - if (RCT_DEBUG) { - RCTAssert(!events || [events isKindOfClass:[NSArray class]], - @"customDirectEventTypes must return an array, but %@ returned %@", - _managerClass, [events class]); - } for (NSString *event in events) { [directEvents addObject:RCTNormalizeInputEventName(event)]; } } -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" NSMutableArray *bubblingEvents = [NSMutableArray new]; if (RCTClassOverridesInstanceMethod(_managerClass, @selector(customBubblingEventTypes))) { -#pragma clang diagnostic pop NSArray *events = [self.manager customBubblingEventTypes]; - if (RCT_DEBUG) { - RCTAssert(!events || [events isKindOfClass:[NSArray class]], - @"customBubblingEventTypes must return an array, but %@ returned %@", - _managerClass, [events class]); - } for (NSString *event in events) { [bubblingEvents addObject:RCTNormalizeInputEventName(event)]; } } +#pragma clang diagnostic pop unsigned int count = 0; NSMutableDictionary *propTypes = [NSMutableDictionary new]; Method *methods = class_copyMethodList(object_getClass(_managerClass), &count); for (unsigned int i = 0; i < count; i++) { - Method method = methods[i]; - SEL selector = method_getName(method); - NSString *methodName = NSStringFromSelector(selector); - if ([methodName hasPrefix:@"propConfig"]) { - NSRange nameRange = [methodName rangeOfString:@"_"]; - if (nameRange.length) { - NSString *name = [methodName substringFromIndex:nameRange.location + 1]; - NSString *type = ((NSArray *(*)(id, SEL))objc_msgSend)(_managerClass, selector)[0]; - if (RCT_DEBUG && propTypes[name] && ![propTypes[name] isEqualToString:type]) { - RCTLogError(@"Property '%@' of component '%@' redefined from '%@' " - "to '%@'", name, _name, propTypes[name], type); - } + SEL selector = method_getName(methods[i]); + const char *selectorName = sel_getName(selector); + if (strncmp(selectorName, "propConfig_", strlen("propConfig_")) != 0) { + continue; + } - if ([type isEqualToString:@"RCTBubblingEventBlock"]) { - [bubblingEvents addObject:RCTNormalizeInputEventName(name)]; - propTypes[name] = @"BOOL"; - } else if ([type isEqualToString:@"RCTDirectEventBlock"]) { - [directEvents addObject:RCTNormalizeInputEventName(name)]; - propTypes[name] = @"BOOL"; - } else { - propTypes[name] = type; - } - } + NSString *name = @(selectorName + strlen("propConfig_")); + NSString *type = ((NSArray *(*)(id, SEL))objc_msgSend)(_managerClass, selector)[0]; + if (RCT_DEBUG && propTypes[name] && ![propTypes[name] isEqualToString:type]) { + RCTLogError(@"Property '%@' of component '%@' redefined from '%@' " + "to '%@'", name, _name, propTypes[name], type); + } + + if ([type isEqualToString:@"RCTBubblingEventBlock"]) { + [bubblingEvents addObject:RCTNormalizeInputEventName(name)]; + propTypes[name] = @"BOOL"; + } else if ([type isEqualToString:@"RCTDirectEventBlock"]) { + [directEvents addObject:RCTNormalizeInputEventName(name)]; + propTypes[name] = @"BOOL"; + } else { + propTypes[name] = type; } } free(methods); - if (RCT_DEBUG) { - for (NSString *event in directEvents) { - if ([bubblingEvents containsObject:event]) { - RCTLogError(@"Component '%@' registered '%@' as both a bubbling event " - "and a direct event", _name, event); - } - } - for (NSString *event in bubblingEvents) { - if ([directEvents containsObject:event]) { - RCTLogError(@"Component '%@' registered '%@' as both a bubbling event " - "and a direct event", _name, event); - } +#if RCT_DEBUG + for (NSString *event in directEvents) { + if ([bubblingEvents containsObject:event]) { + RCTLogError(@"Component '%@' registered '%@' as both a bubbling event " + "and a direct event", _name, event); } } + for (NSString *event in bubblingEvents) { + if ([directEvents containsObject:event]) { + RCTLogError(@"Component '%@' registered '%@' as both a bubbling event " + "and a direct event", _name, event); + } + } +#endif return @{ - @"propTypes" : propTypes, - @"directEvents" : directEvents, - @"bubblingEvents" : bubblingEvents, + @"propTypes": propTypes, + @"directEvents": directEvents, + @"bubblingEvents": bubblingEvents, }; }