Skip to content

Commit 8b19d36

Browse files
authored
feat: remake first measure logic to not use a static member (#288)
<!-- Thanks for submitting a pull request! We appreciate you spending the time to work on these changes. Please follow the template so that the reviewers can easily understand what the code changes affect --> # Summary First render (or rather render without an accessible Component View) used a mock component view for measurements as a static member of the Shadow Node. For obvious reasons this won't work with multiple inputs on the same screen. Original motivation for having mock as a member was to have it created as soon as possible (Shadow Node constructor) to make sure it can be measured on the first render. Turns out it can be very well created just when needed (as long as on main thread) without any first render performance losses. This PR remakes and simplifies this approach so that we don't need a static member anymore. ## Test Plan Run iOS example app and add a simple state to conditionally render the component. Record its first renders and notice it still properly is rendered with the proper height at once, no stutters or jumps. ## Screenshots / Videos -- ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ✅ | | Android | ❌ |
1 parent 4073a47 commit 8b19d36

2 files changed

Lines changed: 9 additions & 26 deletions

File tree

ios/internals/EnrichedTextInputViewShadowNode.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ class EnrichedTextInputViewShadowNode : public ConcreteViewShadowNode<
3535

3636
private:
3737
int localForceHeightRecalculationCounter_;
38-
static id mockTextInputView_;
39-
void setupMockTextInputView_();
38+
id setupMockTextInputView_() const;
4039
};
4140

4241
} // namespace facebook::react

ios/internals/EnrichedTextInputViewShadowNode.mm

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,25 @@
88
namespace facebook::react {
99

1010
extern const char EnrichedTextInputViewComponentName[] = "EnrichedTextInputView";
11-
id EnrichedTextInputViewShadowNode::mockTextInputView_ = nullptr;
1211

1312
EnrichedTextInputViewShadowNode::EnrichedTextInputViewShadowNode(
1413
const ShadowNodeFragment& fragment,
1514
const ShadowNodeFamily::Shared& family,
1615
ShadowNodeTraits traits
1716
): ConcreteViewShadowNode(fragment, family, traits) {
1817
localForceHeightRecalculationCounter_ = 0;
19-
20-
// mock text input needs to be initialized on the main thread
21-
if([NSThread isMainThread]) {
22-
setupMockTextInputView_();
23-
} else {
24-
dispatch_sync(dispatch_get_main_queue(), ^{
25-
setupMockTextInputView_();
26-
});
27-
}
2818
}
2919

3020
// mock input is used for the first measure calls that need to be done when the real input isn't defined yet
31-
void EnrichedTextInputViewShadowNode::setupMockTextInputView_() {
21+
id EnrichedTextInputViewShadowNode::setupMockTextInputView_() const {
3222
// it's rendered far away from the viewport
3323
const int veryFarAway = 20000;
3424
const int mockSize = 1000;
35-
mockTextInputView_ = [[EnrichedTextInputView alloc] initWithFrame:(CGRectMake(veryFarAway, veryFarAway, mockSize, mockSize))];
25+
EnrichedTextInputView *mockTextInputView_ = [[EnrichedTextInputView alloc] initWithFrame:(CGRectMake(veryFarAway, veryFarAway, mockSize, mockSize))];
3626
const auto props = this->getProps();
37-
((EnrichedTextInputView *)mockTextInputView_)->blockEmitting = YES;
27+
mockTextInputView_->blockEmitting = YES;
3828
[mockTextInputView_ updateProps:props oldProps:nullptr];
29+
return mockTextInputView_;
3930
}
4031

4132
EnrichedTextInputViewShadowNode::EnrichedTextInputViewShadowNode(
@@ -65,11 +56,6 @@
6556
EnrichedTextInputView *typedComponentObject = (EnrichedTextInputView *) componentObject;
6657

6758
if(typedComponentObject != nullptr) {
68-
// remove the mock input on the first render with a defined real input
69-
if(mockTextInputView_ != nullptr) {
70-
mockTextInputView_ = nullptr;
71-
}
72-
7359
__block CGSize estimatedSize;
7460

7561
// synchronously dispatch to main thread if needed
@@ -87,18 +73,16 @@
8773
};
8874
}
8975
} else {
90-
if(mockTextInputView_ == nullptr) {
91-
return Size();
92-
}
93-
9476
__block CGSize estimatedSize;
9577

9678
// synchronously dispatch to main thread if needed
9779
if([NSThread isMainThread]) {
98-
estimatedSize = [mockTextInputView_ measureSize:layoutConstraints.maximumSize.width];
80+
EnrichedTextInputView *mockTextInputView = setupMockTextInputView_();
81+
estimatedSize = [mockTextInputView measureSize:layoutConstraints.maximumSize.width];
9982
} else {
10083
dispatch_sync(dispatch_get_main_queue(), ^{
101-
estimatedSize = [mockTextInputView_ measureSize:layoutConstraints.maximumSize.width];
84+
EnrichedTextInputView *mockTextInputView = setupMockTextInputView_();
85+
estimatedSize = [mockTextInputView measureSize:layoutConstraints.maximumSize.width];
10286
});
10387
}
10488

0 commit comments

Comments
 (0)