Skip to content

Commit beffb10

Browse files
adityasharatfacebook-github-bot
authored andcommitted
Passes in inter stage props to range API
Summary: This diff fixes a bug where the range lifecycle methods do not set inter stage props because the interstage props container is never passed to the API. So the AP was setting the container to null. This would throw an NPE when invoking a range lifecycle with inter stage props. This fix * The interstage props are held in the RangeTuple. * Passed to the callbacks as method args. * The AP and Component APIs have been updated to support this use case. Differential Revision: D43246229 fbshipit-source-id: a840c1608a3fd06b64e360467bc811cbe2a8d22a
1 parent 9a0dcd2 commit beffb10

File tree

6 files changed

+70
-35
lines changed

6 files changed

+70
-35
lines changed

litho-core/src/main/java/com/facebook/litho/LayoutState.java

+13-2
Original file line numberDiff line numberDiff line change
@@ -926,8 +926,19 @@ private static void collectResults(
926926
}
927927

928928
for (WorkingRangeContainer.Registration registration : registrations) {
929-
layoutState.mWorkingRangeContainer.registerWorkingRange(
930-
registration.mName, registration.mWorkingRange, registration.mScopedComponentInfo);
929+
if (component instanceof SpecGeneratedComponent) {
930+
layoutState.mWorkingRangeContainer.registerWorkingRange(
931+
registration.mName,
932+
registration.mWorkingRange,
933+
registration.mScopedComponentInfo,
934+
(InterStagePropsContainer) result.getLayoutData());
935+
} else {
936+
layoutState.mWorkingRangeContainer.registerWorkingRange(
937+
registration.mName,
938+
registration.mWorkingRange,
939+
registration.mScopedComponentInfo,
940+
null);
941+
}
931942
}
932943
}
933944

litho-core/src/main/java/com/facebook/litho/SpecGeneratedComponent.java

+8-2
Original file line numberDiff line numberDiff line change
@@ -276,11 +276,17 @@ StateContainer createInitialStateContainer(ComponentContext c) {
276276
return null;
277277
}
278278

279-
protected void dispatchOnEnteredRange(ComponentContext c, String name) {
279+
protected void dispatchOnEnteredRange(
280+
final ComponentContext c,
281+
final String name,
282+
final @Nullable InterStagePropsContainer interStageProps) {
280283
// Do nothing by default
281284
}
282285

283-
protected void dispatchOnExitedRange(ComponentContext c, String name) {
286+
protected void dispatchOnExitedRange(
287+
final ComponentContext c,
288+
final String name,
289+
final @Nullable InterStagePropsContainer interStageProps) {
284290
// Do nothing by default
285291
}
286292

litho-core/src/main/java/com/facebook/litho/WorkingRangeContainer.java

+14-6
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,17 @@ class WorkingRangeContainer {
4141
void registerWorkingRange(
4242
final String name,
4343
final WorkingRange workingRange,
44-
final ScopedComponentInfo scopedComponentInfo) {
44+
final ScopedComponentInfo scopedComponentInfo,
45+
final @Nullable InterStagePropsContainer interStageProps) {
4546
if (mWorkingRanges == null) {
4647
mWorkingRanges = new LinkedHashMap<>();
4748
}
4849

4950
final String key = name + "_" + workingRange.hashCode();
5051
final RangeTuple rangeTuple = mWorkingRanges.get(key);
5152
if (rangeTuple == null) {
52-
mWorkingRanges.put(key, new RangeTuple(name, workingRange, scopedComponentInfo));
53+
mWorkingRanges.put(
54+
key, new RangeTuple(name, workingRange, scopedComponentInfo, interStageProps));
5355
} else {
5456
rangeTuple.addComponent(scopedComponentInfo);
5557
}
@@ -88,7 +90,8 @@ && isEnteringRange(
8890
firstFullyVisibleIndex,
8991
lastFullyVisibleIndex)) {
9092
try {
91-
component.dispatchOnEnteredRange(scopedContext, rangeTuple.mName);
93+
component.dispatchOnEnteredRange(
94+
scopedContext, rangeTuple.mName, rangeTuple.mInterStagePropsContainer);
9295
} catch (Exception e) {
9396
ComponentUtils.handle(scopedContext, e);
9497
}
@@ -103,7 +106,8 @@ && isExitingRange(
103106
firstFullyVisibleIndex,
104107
lastFullyVisibleIndex)) {
105108
try {
106-
component.dispatchOnExitedRange(scopedContext, rangeTuple.mName);
109+
component.dispatchOnExitedRange(
110+
scopedContext, rangeTuple.mName, rangeTuple.mInterStagePropsContainer);
107111
} catch (Exception e) {
108112
ComponentUtils.handle(scopedContext, e);
109113
}
@@ -134,7 +138,8 @@ void dispatchOnExitedRangeIfNeeded(WorkingRangeStatusHandler statusHandler) {
134138
String globalKey = scopedContext.getGlobalKey();
135139
if (statusHandler.isInRange(rangeTuple.mName, component, globalKey)) {
136140
try {
137-
component.dispatchOnExitedRange(scopedContext, rangeTuple.mName);
141+
component.dispatchOnExitedRange(
142+
scopedContext, rangeTuple.mName, rangeTuple.mInterStagePropsContainer);
138143
} catch (Exception e) {
139144
ComponentUtils.handle(scopedContext, e);
140145
}
@@ -189,15 +194,18 @@ static class RangeTuple {
189194
final String mName;
190195
final WorkingRange mWorkingRange;
191196
final List<ScopedComponentInfo> mScopedComponentInfos;
197+
final @Nullable InterStagePropsContainer mInterStagePropsContainer;
192198

193199
RangeTuple(
194200
final String name,
195201
final WorkingRange workingRange,
196-
final ScopedComponentInfo scopedComponentInfo) {
202+
final ScopedComponentInfo scopedComponentInfo,
203+
final @Nullable InterStagePropsContainer interStagePropsContainer) {
197204
mName = name;
198205
mWorkingRange = workingRange;
199206
mScopedComponentInfos = new ArrayList<>();
200207
mScopedComponentInfos.add(scopedComponentInfo);
208+
mInterStagePropsContainer = interStagePropsContainer;
201209
}
202210

203211
void addComponent(final ScopedComponentInfo scopedComponentInfo) {

litho-it/src/test/java/com/facebook/litho/WorkingRangeContainerTest.java

+10-9
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import static org.assertj.core.api.Assertions.assertThat;
2020
import static org.mockito.ArgumentMatchers.isA;
21+
import static org.mockito.ArgumentMatchers.isNull;
2122
import static org.mockito.Mockito.doNothing;
2223
import static org.mockito.Mockito.mock;
2324
import static org.mockito.Mockito.times;
@@ -71,7 +72,7 @@ public void setup() {
7172

7273
@Test
7374
public void testRegisterWorkingRange() {
74-
mWorkingRangeContainer.registerWorkingRange(NAME, mWorkingRange, mScopedComponentInfo);
75+
mWorkingRangeContainer.registerWorkingRange(NAME, mWorkingRange, mScopedComponentInfo, null);
7576

7677
final Map<String, RangeTuple> workingRanges =
7778
mWorkingRangeContainer.getWorkingRangesForTestOnly();
@@ -88,7 +89,7 @@ public void testRegisterWorkingRange() {
8889

8990
@Test
9091
public void testIsEnteredRange() {
91-
RangeTuple rangeTuple = new RangeTuple(NAME, mWorkingRange, mScopedComponentInfo);
92+
RangeTuple rangeTuple = new RangeTuple(NAME, mWorkingRange, mScopedComponentInfo, null);
9293
WorkingRange workingRange = rangeTuple.mWorkingRange;
9394

9495
assertThat(WorkingRangeContainer.isEnteringRange(workingRange, 0, 0, 1, 0, 1)).isEqualTo(true);
@@ -97,7 +98,7 @@ public void testIsEnteredRange() {
9798

9899
@Test
99100
public void testIsExitedRange() {
100-
RangeTuple rangeTuple = new RangeTuple(NAME, mWorkingRange, mScopedComponentInfo);
101+
RangeTuple rangeTuple = new RangeTuple(NAME, mWorkingRange, mScopedComponentInfo, null);
101102
WorkingRange workingRange = rangeTuple.mWorkingRange;
102103

103104
assertThat(WorkingRangeContainer.isExitingRange(workingRange, 0, 0, 1, 0, 1)).isEqualTo(false);
@@ -107,28 +108,28 @@ public void testIsExitedRange() {
107108
@Test
108109
public void testDispatchOnExitedRangeIfNeeded() {
109110
TestWorkingRange workingRange = new TestWorkingRange();
110-
mWorkingRangeContainer.registerWorkingRange(NAME, workingRange, mScopedComponentInfo);
111+
mWorkingRangeContainer.registerWorkingRange(NAME, workingRange, mScopedComponentInfo, null);
111112

112113
TestWorkingRange workingRange2 = new TestWorkingRange();
113-
mWorkingRangeContainer.registerWorkingRange(NAME, workingRange2, mScopedComponentInfo2);
114+
mWorkingRangeContainer.registerWorkingRange(NAME, workingRange2, mScopedComponentInfo2, null);
114115

115116
final WorkingRangeStatusHandler statusHandler = new WorkingRangeStatusHandler();
116117
statusHandler.setStatus(
117118
NAME, mComponent, "component", WorkingRangeStatusHandler.STATUS_IN_RANGE);
118119
doNothing()
119120
.when(mComponent)
120-
.dispatchOnExitedRange(isA(ComponentContext.class), isA(String.class));
121+
.dispatchOnExitedRange(isA(ComponentContext.class), isA(String.class), isNull());
121122

122123
statusHandler.setStatus(
123124
NAME, mComponent2, "component2", WorkingRangeStatusHandler.STATUS_OUT_OF_RANGE);
124125
doNothing()
125126
.when(mComponent2)
126-
.dispatchOnExitedRange(isA(ComponentContext.class), isA(String.class));
127+
.dispatchOnExitedRange(isA(ComponentContext.class), isA(String.class), isNull());
127128

128129
mWorkingRangeContainer.dispatchOnExitedRangeIfNeeded(statusHandler);
129130

130-
verify(mComponent, times(1)).dispatchOnExitedRange(mComponentContext, NAME);
131-
verify(mComponent2, times(0)).dispatchOnExitedRange(mComponentContext, NAME);
131+
verify(mComponent, times(1)).dispatchOnExitedRange(mComponentContext, NAME, null);
132+
verify(mComponent2, times(0)).dispatchOnExitedRange(mComponentContext, NAME, null);
132133
}
133134

134135
private static class TestWorkingRange implements WorkingRange {

litho-it/src/test/java/com/facebook/litho/specmodels/generator/WorkingRangeGeneratorTest.java

+16-10
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,15 @@ public void testGenerateDispatchOnEnteredRange() {
8383
assertThat(WorkingRangeGenerator.generateDispatchOnEnteredRangeMethod(mSpecModel).toString())
8484
.isEqualTo(
8585
"@java.lang.Override\n"
86-
+ "public void dispatchOnEnteredRange(com.facebook.litho.ComponentContext c, java.lang.String name) {\n"
86+
+ "public void dispatchOnEnteredRange(com.facebook.litho.ComponentContext c, java.lang.String name,\n"
87+
+ " com.facebook.litho.InterStagePropsContainer interStageProps) {\n"
8788
+ " switch (name) {\n"
8889
+ " case \"enter\": {\n"
89-
+ " testEnteredRangeMethod(c);\n"
90+
+ " testEnteredRangeMethod(c, interStageProps);\n"
9091
+ " return;\n"
9192
+ " }\n"
9293
+ " case \"prefetch\": {\n"
93-
+ " testEnteredPrefetchMethod(c);\n"
94+
+ " testEnteredPrefetchMethod(c, interStageProps);\n"
9495
+ " return;\n"
9596
+ " }\n"
9697
+ " }\n"
@@ -102,14 +103,15 @@ public void testGenerateDispatchOnExitedRange() {
102103
assertThat(WorkingRangeGenerator.generateDispatchOnExitedRangeMethod(mSpecModel).toString())
103104
.isEqualTo(
104105
"@java.lang.Override\n"
105-
+ "public void dispatchOnExitedRange(com.facebook.litho.ComponentContext c, java.lang.String name) {\n"
106+
+ "public void dispatchOnExitedRange(com.facebook.litho.ComponentContext c, java.lang.String name,\n"
107+
+ " com.facebook.litho.InterStagePropsContainer interStageProps) {\n"
106108
+ " switch (name) {\n"
107109
+ " case \"exit\": {\n"
108-
+ " testExitedRangeMethod(c);\n"
110+
+ " testExitedRangeMethod(c, interStageProps);\n"
109111
+ " return;\n"
110112
+ " }\n"
111113
+ " case \"prefetch\": {\n"
112-
+ " testExitedPrefetchMethod(c);\n"
114+
+ " testExitedPrefetchMethod(c, interStageProps);\n"
113115
+ " return;\n"
114116
+ " }\n"
115117
+ " }\n"
@@ -125,7 +127,8 @@ public void testGenerateWorkingRangeMethodDelegates() {
125127

126128
assertThat(dataHolder.getMethodSpecs().get(0).toString())
127129
.isEqualTo(
128-
"private void testEnteredRangeMethod(com.facebook.litho.ComponentContext c) {\n"
130+
"private void testEnteredRangeMethod(com.facebook.litho.ComponentContext c,\n"
131+
+ " com.facebook.litho.InterStagePropsContainer interStageProps) {\n"
129132
+ " TestSpec.testEnteredRangeMethod(\n"
130133
+ " (com.facebook.litho.ComponentContext) c,\n"
131134
+ " (boolean) arg0,\n"
@@ -134,7 +137,8 @@ public void testGenerateWorkingRangeMethodDelegates() {
134137

135138
assertThat(dataHolder.getMethodSpecs().get(1).toString())
136139
.isEqualTo(
137-
"private void testExitedRangeMethod(com.facebook.litho.ComponentContext c) {\n"
140+
"private void testExitedRangeMethod(com.facebook.litho.ComponentContext c,\n"
141+
+ " com.facebook.litho.InterStagePropsContainer interStageProps) {\n"
138142
+ " TestSpec.testExitedRangeMethod(\n"
139143
+ " (com.facebook.litho.ComponentContext) c,\n"
140144
+ " (T) arg2,\n"
@@ -143,7 +147,8 @@ public void testGenerateWorkingRangeMethodDelegates() {
143147

144148
assertThat(dataHolder.getMethodSpecs().get(2).toString())
145149
.isEqualTo(
146-
"private void testEnteredPrefetchMethod(com.facebook.litho.ComponentContext c) {\n"
150+
"private void testEnteredPrefetchMethod(com.facebook.litho.ComponentContext c,\n"
151+
+ " com.facebook.litho.InterStagePropsContainer interStageProps) {\n"
147152
+ " TestSpec.testEnteredPrefetchMethod(\n"
148153
+ " (com.facebook.litho.ComponentContext) c,\n"
149154
+ " (boolean) arg0,\n"
@@ -152,7 +157,8 @@ public void testGenerateWorkingRangeMethodDelegates() {
152157

153158
assertThat(dataHolder.getMethodSpecs().get(3).toString())
154159
.isEqualTo(
155-
"private void testExitedPrefetchMethod(com.facebook.litho.ComponentContext c) {\n"
160+
"private void testExitedPrefetchMethod(com.facebook.litho.ComponentContext c,\n"
161+
+ " com.facebook.litho.InterStagePropsContainer interStageProps) {\n"
156162
+ " TestSpec.testExitedPrefetchMethod(\n"
157163
+ " (com.facebook.litho.ComponentContext) c,\n"
158164
+ " (T) arg2,\n"

litho-processor/src/main/java/com/facebook/litho/specmodels/generator/WorkingRangeGenerator.java

+9-6
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,16 @@ static MethodSpec generateDispatchOnEnteredRangeMethod(SpecModel specModel) {
5959
.addAnnotation(Override.class)
6060
.returns(TypeName.VOID)
6161
.addParameter(specModel.getContextClass(), "c")
62-
.addParameter(ClassNames.STRING, "name");
62+
.addParameter(ClassNames.STRING, "name")
63+
.addParameter(ClassNames.INTER_STAGE_PROPS_CONTAINER, "interStageProps");
6364

6465
methodBuilder.beginControlFlow("switch (name)");
6566

6667
for (WorkingRangeMethodModel model : specModel.getWorkingRangeMethods()) {
6768
if (model.enteredRangeModel != null && model.enteredRangeModel.typeModel != null) {
6869
final String nameInAnnotation = model.enteredRangeModel.typeModel.name;
6970
methodBuilder.beginControlFlow("case \"$L\":", nameInAnnotation);
70-
methodBuilder.addStatement("$L(c)", model.enteredRangeModel.name);
71+
methodBuilder.addStatement("$L(c, interStageProps)", model.enteredRangeModel.name);
7172
methodBuilder.addStatement("return");
7273
methodBuilder.endControlFlow();
7374
}
@@ -84,15 +85,16 @@ static MethodSpec generateDispatchOnExitedRangeMethod(SpecModel specModel) {
8485
.addAnnotation(Override.class)
8586
.returns(TypeName.VOID)
8687
.addParameter(specModel.getContextClass(), "c")
87-
.addParameter(ClassNames.STRING, "name");
88+
.addParameter(ClassNames.STRING, "name")
89+
.addParameter(ClassNames.INTER_STAGE_PROPS_CONTAINER, "interStageProps");
8890

8991
methodBuilder.beginControlFlow("switch (name)");
9092

9193
for (WorkingRangeMethodModel model : specModel.getWorkingRangeMethods()) {
9294
if (model.exitedRangeModel != null && model.exitedRangeModel.typeModel != null) {
9395
final String nameInAnnotation = model.exitedRangeModel.typeModel.name;
9496
methodBuilder.beginControlFlow("case \"$L\":", nameInAnnotation);
95-
methodBuilder.addStatement("$L(c)", model.exitedRangeModel.name);
97+
methodBuilder.addStatement("$L(c, interStageProps)", model.exitedRangeModel.name);
9698
methodBuilder.addStatement("return");
9799
methodBuilder.endControlFlow();
98100
}
@@ -124,7 +126,8 @@ private static MethodSpec generateWorkingRangeMethodDelegate(
124126
MethodSpec.methodBuilder(methodModel.name.toString())
125127
.addModifiers(Modifier.PRIVATE)
126128
.returns(TypeName.VOID)
127-
.addParameter(ClassNames.COMPONENT_CONTEXT, "c");
129+
.addParameter(ClassNames.COMPONENT_CONTEXT, "c")
130+
.addParameter(ClassNames.INTER_STAGE_PROPS_CONTAINER, "interStageProps");
128131

129132
final CodeBlock.Builder delegation = CodeBlock.builder();
130133

@@ -134,7 +137,7 @@ private static MethodSpec generateWorkingRangeMethodDelegate(
134137
"$L $L = $L",
135138
ClassNames.INTER_STAGE_PROPS_CONTAINER,
136139
ComponentBodyGenerator.LOCAL_INTER_STAGE_PROPS_CONTAINER_NAME,
137-
"null");
140+
"interStageProps");
138141
}
139142

140143
final String sourceDelegateAccessor = SpecModelUtils.getSpecAccessor(specModel);

0 commit comments

Comments
 (0)