mirror of
https://github.com/status-im/react-native.git
synced 2025-01-28 02:04:55 +00:00
[ReactNative] Stop traversing the whole view hierarchy every frame
Summary: @public `RCTUIManager` would traverse the whole view hierarchy every time there was any call from JS to Native to call `reactBridgeDidFinishTransaction` on the views that would respond to it. This is a deprecated method that is only implemented by 3 classes, so for now we keep track of these views as they're created and just iterate through them on updates. Test Plan: > NOTE: I tested this on UIExplorer, since the internally none of the classes are used I tried to keep it simple, so I added the following to the old code: ``` __block NSUInteger count = 0; UIView *rootView = _viewRegistry[rootViewTag]; RCTTraverseViewNodes(rootView, ^(id<RCTViewNodeProtocol> view) { count ++; if ([view respondsToSelector:@selector(reactBridgeDidFinishTransaction)]) { [view reactBridgeDidFinishTransaction]; } }); NSLog(@"Views iterated: %zd", count); ``` The output after scrolling 20 sections of the `<ListView> - Paging` example was ``` 2015-06-01 00:47:07.351 UIExplorer[67675:1709506] Views iterated: 1549 ``` *every frame* After the change ``` for (id<RCTViewNodeProtocol> node in _bridgeTransactionListeners) { [node reactBridgeDidFinishTransaction]; } NSLog(@"Views iterated: %zd", _bridgeTransactionListeners.count); ``` ``` 2015-06-01 00:51:23.715 UIExplorer[70355:1716465] Views iterated: 3 ``` No matter how many pages are loaded, the output is always 3.
This commit is contained in:
parent
df58789f22
commit
b03446e27e
@ -197,7 +197,8 @@ static UIViewAnimationCurve UIViewAnimationCurveFromRCTAnimationType(RCTAnimatio
|
||||
NSMutableDictionary *_defaultViews; // Main thread only
|
||||
NSDictionary *_viewManagers;
|
||||
NSDictionary *_viewConfigs;
|
||||
NSUInteger _rootTag;
|
||||
|
||||
NSMutableSet *_bridgeTransactionListeners;
|
||||
}
|
||||
|
||||
@synthesize bridge = _bridge;
|
||||
@ -263,7 +264,8 @@ static NSDictionary *RCTViewConfigForModule(Class managerClass, NSString *viewNa
|
||||
// Internal resources
|
||||
_pendingUIBlocks = [[NSMutableArray alloc] init];
|
||||
_rootViewTags = [[NSMutableSet alloc] init];
|
||||
_rootTag = 1;
|
||||
|
||||
_bridgeTransactionListeners = [[NSMutableSet alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@ -287,6 +289,7 @@ static NSDictionary *RCTViewConfigForModule(Class managerClass, NSString *viewNa
|
||||
_rootViewTags = nil;
|
||||
_shadowViewRegistry = nil;
|
||||
_viewRegistry = nil;
|
||||
_bridgeTransactionListeners = nil;
|
||||
_bridge = nil;
|
||||
|
||||
[_pendingUIBlocksLock lock];
|
||||
@ -397,6 +400,10 @@ static NSDictionary *RCTViewConfigForModule(Class managerClass, NSString *viewNa
|
||||
[(id<RCTInvalidating>)subview invalidate];
|
||||
}
|
||||
registry[subview.reactTag] = nil;
|
||||
|
||||
if (registry == _viewRegistry) {
|
||||
[_bridgeTransactionListeners removeObject:subview];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -482,7 +489,6 @@ static NSDictionary *RCTViewConfigForModule(Class managerClass, NSString *viewNa
|
||||
}
|
||||
|
||||
// Perform layout (possibly animated)
|
||||
NSNumber *rootViewTag = rootShadowView.reactTag;
|
||||
return ^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
|
||||
RCTResponseSenderBlock callback = self->_layoutAnimation.callback;
|
||||
__block NSInteger completionsCalled = 0;
|
||||
@ -547,17 +553,11 @@ static NSDictionary *RCTViewConfigForModule(Class managerClass, NSString *viewNa
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerate all active (attached to a parent) views and call
|
||||
* reactBridgeDidFinishTransaction on them if they implement it.
|
||||
* TODO: this is quite inefficient. If this was handled via the
|
||||
* ViewManager instead, it could be done more efficiently.
|
||||
* TODO(tadeu): Remove it once and for all
|
||||
*/
|
||||
UIView *rootView = _viewRegistry[rootViewTag];
|
||||
RCTTraverseViewNodes(rootView, ^(id<RCTViewNodeProtocol> view) {
|
||||
if ([view respondsToSelector:@selector(reactBridgeDidFinishTransaction)]) {
|
||||
[view reactBridgeDidFinishTransaction];
|
||||
}
|
||||
});
|
||||
for (id<RCTViewNodeProtocol> node in _bridgeTransactionListeners) {
|
||||
[node reactBridgeDidFinishTransaction];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -844,6 +844,10 @@ RCT_EXPORT_METHOD(createView:(NSNumber *)reactTag
|
||||
view.layer.allowsGroupOpacity = YES; // required for touch handling
|
||||
}
|
||||
RCTSetViewProps(props, view, uiManager->_defaultViews[viewName], manager);
|
||||
|
||||
if ([view respondsToSelector:@selector(reactBridgeDidFinishTransaction)]) {
|
||||
[uiManager->_bridgeTransactionListeners addObject:view];
|
||||
}
|
||||
}
|
||||
viewRegistry[reactTag] = view;
|
||||
}];
|
||||
|
Loading…
x
Reference in New Issue
Block a user