@@ -66,6 +66,9 @@ @implementation RCTUIManager
6666 NSMutableDictionary <NSNumber *, RCTShadowView *> *_shadowViewRegistry; // RCT thread only
6767 NSMutableDictionary <NSNumber *, UIView *> *_viewRegistry; // Main thread only
6868
69+ NSMapTable <RCTShadowView *, NSArray <NSString *> *> *_shadowViewsWithUpdatedProps; // UIManager queue only.
70+ NSHashTable <RCTShadowView *> *_shadowViewsWithUpdatedChildren; // UIManager queue only.
71+
6972 // Keyed by viewName
7073 NSDictionary *_componentDataByName;
7174}
@@ -138,6 +141,9 @@ - (void)setBridge:(RCTBridge *)bridge
138141 _shadowViewRegistry = [NSMutableDictionary new ];
139142 _viewRegistry = [NSMutableDictionary new ];
140143
144+ _shadowViewsWithUpdatedProps = [NSMapTable weakToStrongObjectsMapTable ];
145+ _shadowViewsWithUpdatedChildren = [NSHashTable weakObjectsHashTable ];
146+
141147 // Internal resources
142148 _pendingUIBlocks = [NSMutableArray new ];
143149 _rootViewTags = [NSMutableSet new ];
@@ -839,6 +845,8 @@ - (void)_removeChildren:(NSArray<UIView *> *)children
839845 RCTSetChildren (containerTag, reactTags,
840846 (NSDictionary <NSNumber *, id <RCTComponent>> *)viewRegistry);
841847 }];
848+
849+ [self _shadowViewDidReceiveUpdatedChildren: _shadowViewRegistry[containerTag]];
842850}
843851
844852static void RCTSetChildren (NSNumber *containerTag,
@@ -879,6 +887,8 @@ static void RCTSetChildren(NSNumber *containerTag,
879887 removeAtIndices: removeAtIndices
880888 registry: (NSMutableDictionary <NSNumber *, id <RCTComponent>> *)viewRegistry];
881889 }];
890+
891+ [self _shadowViewDidReceiveUpdatedChildren: _shadowViewRegistry[containerTag]];
882892}
883893
884894- (void )_manageChildren : (NSNumber *)containerTag
@@ -972,6 +982,13 @@ - (void)_manageChildren:(NSNumber *)containerTag
972982#endif
973983 }
974984 });
985+
986+ [self addUIBlock: ^(__unused RCTUIManager *uiManager, NSDictionary <NSNumber *, UIView *> *viewRegistry) {
987+ UIView *view = viewRegistry[reactTag];
988+ [componentData setProps: props forView: view];
989+ }];
990+
991+ [self _shadowView: shadowView didReceiveUpdatedProps: [props allKeys ]];
975992}
976993
977994RCT_EXPORT_METHOD (updateView:(nonnull NSNumber *)reactTag
@@ -986,6 +1003,8 @@ - (void)_manageChildren:(NSNumber *)containerTag
9861003 UIView *view = viewRegistry[reactTag];
9871004 [componentData setProps: props forView: view];
9881005 }];
1006+
1007+ [self _shadowView: shadowView didReceiveUpdatedProps: [props allKeys ]];
9891008}
9901009
9911010- (void )synchronouslyUpdateViewOnUIThread : (NSNumber *)reactTag
@@ -1067,6 +1086,9 @@ - (void)_layoutAndMount
10671086 [self addUIBlock: uiBlock];
10681087 }
10691088
1089+ [self _dispatchPropsDidChangeEvents ];
1090+ [self _dispatchChildrenDidChangeEvents ];
1091+
10701092 [_observerCoordinator uiManagerWillPerformLayout: self ];
10711093
10721094 // Perform layout
@@ -1135,6 +1157,75 @@ - (void)setNeedsLayout
11351157 }
11361158}
11371159
1160+ - (void )_shadowView : (RCTShadowView *)shadowView didReceiveUpdatedProps : (NSArray <NSString *> *)props
1161+ {
1162+ // We collect a set with changed `shadowViews` and its changed props,
1163+ // so we have to maintain this collection properly.
1164+ NSArray <NSString *> *previousProps;
1165+ if ((previousProps = [_shadowViewsWithUpdatedProps objectForKey: shadowView])) {
1166+ // Merging already registred changed props and new ones.
1167+ NSMutableSet *set = [NSMutableSet setWithArray: previousProps];
1168+ [set addObjectsFromArray: props];
1169+ props = [set allObjects ];
1170+ }
1171+
1172+ [_shadowViewsWithUpdatedProps setObject: props forKey: shadowView];
1173+ }
1174+
1175+ - (void )_shadowViewDidReceiveUpdatedChildren : (RCTShadowView *)shadowView
1176+ {
1177+ [_shadowViewsWithUpdatedChildren addObject: shadowView];
1178+ }
1179+
1180+ - (void )_dispatchChildrenDidChangeEvents
1181+ {
1182+ if (_shadowViewsWithUpdatedChildren.count == 0 ) {
1183+ return ;
1184+ }
1185+
1186+ NSHashTable <RCTShadowView *> *shadowViews = _shadowViewsWithUpdatedChildren;
1187+ _shadowViewsWithUpdatedChildren = [NSHashTable weakObjectsHashTable ];
1188+
1189+ NSMutableArray *tags = [NSMutableArray arrayWithCapacity: shadowViews.count];
1190+
1191+ for (RCTShadowView *shadowView in shadowViews) {
1192+ [shadowView didUpdateReactSubviews ];
1193+ [tags addObject: shadowView.reactTag];
1194+ }
1195+
1196+ [self addUIBlock: ^(RCTUIManager *uiManager, NSDictionary <NSNumber *, UIView *> *viewRegistry) {
1197+ for (NSNumber *tag in tags) {
1198+ UIView<RCTComponent> *view = viewRegistry[tag];
1199+ [view didUpdateReactSubviews ];
1200+ }
1201+ }];
1202+ }
1203+
1204+ - (void )_dispatchPropsDidChangeEvents
1205+ {
1206+ if (_shadowViewsWithUpdatedProps.count == 0 ) {
1207+ return ;
1208+ }
1209+
1210+ NSMapTable <RCTShadowView *, NSArray <NSString *> *> *shadowViews = _shadowViewsWithUpdatedProps;
1211+ _shadowViewsWithUpdatedProps = [NSMapTable weakToStrongObjectsMapTable ];
1212+
1213+ NSMapTable <NSNumber *, NSArray <NSString *> *> *tags = [NSMapTable strongToStrongObjectsMapTable ];
1214+
1215+ for (RCTShadowView *shadowView in shadowViews) {
1216+ NSArray <NSString *> *props = [shadowViews objectForKey: shadowView];
1217+ [shadowView didSetProps: props];
1218+ [tags setObject: props forKey: shadowView.reactTag];
1219+ }
1220+
1221+ [self addUIBlock: ^(RCTUIManager *uiManager, NSDictionary <NSNumber *, UIView *> *viewRegistry) {
1222+ for (NSNumber *tag in tags) {
1223+ UIView<RCTComponent> *view = viewRegistry[tag];
1224+ [view didSetProps: [tags objectForKey: tag]];
1225+ }
1226+ }];
1227+ }
1228+
11381229RCT_EXPORT_METHOD (measure:(nonnull NSNumber *)reactTag
11391230 callback:(RCTResponseSenderBlock)callback)
11401231{
0 commit comments