Skip to content

Commit ea2a033

Browse files
authored
feat(Stack): Add support for synchronous state updates on fabric for native stack (#3282)
## Description This PR adds support for synchronous updates in the native stack for React Native 0.82+. Currently, enabling synchronous state updates is possible via an experimental feature flag: `unstable_synchronousStateUpdatesEnabled`. At this time, I haven't found a way to perform synchronous updates on Android, so this PR only includes mocks for that platform. I'm creating a ticket for covering that: software-mansion/react-native-screens-labs#497 Fixes software-mansion/react-native-screens-labs#495 ## Changes - Added feature flags in JS per native component for testing synchronous updates: - synchronousScreenUpdatesEnabled - synchronousHeaderConfigUpdatesEnabled - synchronousHeaderSubviewUpdatesEnabled - Added mocks for android implementation - Added implementation for all native components on iOS that are performing shadow tree state updates ## Screenshots / GIFs ### Before https://github.com/user-attachments/assets/bc21afa9-1e6f-4dbd-9dcf-0319b5d72ac7 ### After https://github.com/user-attachments/assets/e131260d-6667-4652-909c-13be77e6fdf3 ## Test code and steps to reproduce Adding a new example, which is verifying that with synchronous updates enabled, the form sheet content flicker issues are resolved. ## Checklist - [x] Included code example that can be used to test this change - [x] Ensured that CI passes
1 parent 687eee1 commit ea2a033

25 files changed

+271
-16
lines changed

FabricExample/App.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
import App from '../apps';
2+
import { featureFlags } from '../src';
3+
4+
featureFlags.experiment.synchronousScreenUpdatesEnabled = false
5+
featureFlags.experiment.synchronousHeaderConfigUpdatesEnabled = false
6+
featureFlags.experiment.synchronousHeaderSubviewUpdatesEnabled = false
27

38
export default App;

android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,13 @@ class ScreenStackHeaderConfigViewManager :
205205
config.setDirection(direction)
206206
}
207207

208+
// synchronousShadowStateUpdatesEnabled is not available on Android atm,
209+
// however we must override their setters
210+
override fun setSynchronousShadowStateUpdatesEnabled(
211+
config: ScreenStackHeaderConfig?,
212+
value: Boolean,
213+
) = Unit
214+
208215
override fun getExportedCustomDirectEventTypeConstants(): Map<String, Any> =
209216
hashMapOf(
210217
HeaderAttachedEvent.EVENT_NAME to hashMapOf("registrationName" to "onAttached"),

android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubviewManager.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ class ScreenStackHeaderSubviewManager :
5050
Log.w("[RNScreens]", "hidesSharedBackground prop is not available on Android")
5151
}
5252

53+
// synchronousShadowStateUpdatesEnabled is not available on Android atm,
54+
// however we must override their setters
55+
override fun setSynchronousShadowStateUpdatesEnabled(
56+
view: ScreenStackHeaderSubview?,
57+
value: Boolean,
58+
) = Unit
59+
5360
override fun updateState(
5461
view: ScreenStackHeaderSubview,
5562
props: ReactStylesDiffMap?,

android/src/main/java/com/swmansion/rnscreens/ScreenViewManager.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ open class ScreenViewManager :
268268
view?.sheetElevation = value.toFloat()
269269
}
270270

271+
// mark: iOS-only
271272
// these props are not available on Android, however we must override their setters
272273
override fun setFullScreenSwipeEnabled(
273274
view: Screen?,
@@ -334,6 +335,13 @@ open class ScreenViewManager :
334335
value: String?,
335336
) = Unit
336337

338+
override fun setSynchronousShadowStateUpdatesEnabled(
339+
view: Screen?,
340+
value: Boolean,
341+
) = Unit
342+
343+
// END mark: iOS-only
344+
337345
@ReactProp(name = "sheetAllowedDetents")
338346
override fun setSheetAllowedDetents(
339347
view: Screen,

android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenManagerDelegate.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ public void setProperty(T view, String propName, @Nullable Object value) {
134134
case "topScrollEdgeEffect":
135135
mViewManager.setTopScrollEdgeEffect(view, (String) value);
136136
break;
137+
case "synchronousShadowStateUpdatesEnabled":
138+
mViewManager.setSynchronousShadowStateUpdatesEnabled(view, value == null ? false : (boolean) value);
139+
break;
137140
default:
138141
super.setProperty(view, propName, value);
139142
}

android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenManagerInterface.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,5 @@ public interface RNSScreenManagerInterface<T extends View> {
5252
void setLeftScrollEdgeEffect(T view, @Nullable String value);
5353
void setRightScrollEdgeEffect(T view, @Nullable String value);
5454
void setTopScrollEdgeEffect(T view, @Nullable String value);
55+
void setSynchronousShadowStateUpdatesEnabled(T view, boolean value);
5556
}

android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackHeaderConfigManagerDelegate.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ public void setProperty(T view, String propName, @Nullable Object value) {
115115
case "headerRightBarButtonItems":
116116
mViewManager.setHeaderRightBarButtonItems(view, (ReadableArray) value);
117117
break;
118+
case "synchronousShadowStateUpdatesEnabled":
119+
mViewManager.setSynchronousShadowStateUpdatesEnabled(view, value == null ? false : (boolean) value);
120+
break;
118121
default:
119122
super.setProperty(view, propName, value);
120123
}

android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackHeaderConfigManagerInterface.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,5 @@ public interface RNSScreenStackHeaderConfigManagerInterface<T extends View> {
4545
void setTopInsetEnabled(T view, boolean value);
4646
void setHeaderLeftBarButtonItems(T view, @Nullable ReadableArray value);
4747
void setHeaderRightBarButtonItems(T view, @Nullable ReadableArray value);
48+
void setSynchronousShadowStateUpdatesEnabled(T view, boolean value);
4849
}

android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackHeaderSubviewManagerDelegate.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ public void setProperty(T view, String propName, @Nullable Object value) {
2929
case "hidesSharedBackground":
3030
mViewManager.setHidesSharedBackground(view, value == null ? false : (boolean) value);
3131
break;
32+
case "synchronousShadowStateUpdatesEnabled":
33+
mViewManager.setSynchronousShadowStateUpdatesEnabled(view, value == null ? false : (boolean) value);
34+
break;
3235
default:
3336
super.setProperty(view, propName, value);
3437
}

android/src/paper/java/com/facebook/react/viewmanagers/RNSScreenStackHeaderSubviewManagerInterface.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@
1616
public interface RNSScreenStackHeaderSubviewManagerInterface<T extends View> {
1717
void setType(T view, @Nullable String value);
1818
void setHidesSharedBackground(T view, boolean value);
19+
void setSynchronousShadowStateUpdatesEnabled(T view, boolean value);
1920
}

0 commit comments

Comments
 (0)