diff --git a/patches/@react-navigation+core+6.4.11+001+fix-react-strictmode.patch b/patches/@react-navigation+core+6.4.11+001+fix-react-strictmode.patch
new file mode 100644
index 000000000000..8941bb380a79
--- /dev/null
+++ b/patches/@react-navigation+core+6.4.11+001+fix-react-strictmode.patch
@@ -0,0 +1,44 @@
+diff --git a/node_modules/@react-navigation/core/lib/module/useNavigationBuilder.js b/node_modules/@react-navigation/core/lib/module/useNavigationBuilder.js
+index 051520b..6fb49e0 100644
+--- a/node_modules/@react-navigation/core/lib/module/useNavigationBuilder.js
++++ b/node_modules/@react-navigation/core/lib/module/useNavigationBuilder.js
+@@ -174,10 +174,6 @@ export default function useNavigationBuilder(createRouter, options) {
+ getIsInitial
+ } = React.useContext(NavigationStateContext);
+ const stateCleanedUp = React.useRef(false);
+- const cleanUpState = React.useCallback(() => {
+- setCurrentState(undefined);
+- stateCleanedUp.current = true;
+- }, [setCurrentState]);
+ const setState = React.useCallback(state => {
+ if (stateCleanedUp.current) {
+ // State might have been already cleaned up due to unmount
+@@ -291,6 +287,9 @@ export default function useNavigationBuilder(createRouter, options) {
+ // So we override the state object we return to use the latest state as soon as possible
+ state = nextState;
+ React.useEffect(() => {
++ // In strict mode, React will double-invoke effects.
++ // So we need to reset the flag if component was not unmounted
++ stateCleanedUp.current = false;
+ setKey(navigatorKey);
+ if (!getIsInitial()) {
+ // If it's not initial render, we need to update the state
+@@ -300,14 +299,10 @@ export default function useNavigationBuilder(createRouter, options) {
+ }
+ return () => {
+ // We need to clean up state for this navigator on unmount
+- // We do it in a timeout because we need to detect if another navigator mounted in the meantime
+- // For example, if another navigator has started rendering, we should skip cleanup
+- // Otherwise, our cleanup step will cleanup state for the other navigator and re-initialize it
+- setTimeout(() => {
+- if (getCurrentState() !== undefined && getKey() === navigatorKey) {
+- cleanUpState();
+- }
+- }, 0);
++ if (getCurrentState() !== undefined && getKey() === navigatorKey) {
++ setCurrentState(undefined);
++ stateCleanedUp.current = true;
++ }
+ };
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
diff --git a/patches/react-native-reanimated+3.8.1+003+fix-strict-mode.patch b/patches/react-native-reanimated+3.8.1+003+fix-strict-mode.patch
new file mode 100644
index 000000000000..e36d2dd365c0
--- /dev/null
+++ b/patches/react-native-reanimated+3.8.1+003+fix-strict-mode.patch
@@ -0,0 +1,23 @@
+diff --git a/node_modules/react-native-reanimated/lib/module/reanimated2/UpdateProps.js b/node_modules/react-native-reanimated/lib/module/reanimated2/UpdateProps.js
+index e69c581..78b7034 100644
+--- a/node_modules/react-native-reanimated/lib/module/reanimated2/UpdateProps.js
++++ b/node_modules/react-native-reanimated/lib/module/reanimated2/UpdateProps.js
+@@ -7,14 +7,11 @@ import { isFabric, isJest, shouldBeUseWeb } from './PlatformChecker';
+ import { runOnUIImmediately } from './threads';
+ let updateProps;
+ if (shouldBeUseWeb()) {
+- updateProps = (_, updates, maybeViewRef, isAnimatedProps) => {
++ updateProps = (viewDescriptorsSet, updates, maybeViewRef, isAnimatedProps) => {
+ 'worklet';
+-
+- if (maybeViewRef) {
+- maybeViewRef.items.forEach((item, _index) => {
+- _updatePropsJS(updates, item, isAnimatedProps);
+- });
+- }
++ viewDescriptorsSet.value.forEach((viewDescriptor) => {
++ _updatePropsJS(updates, {_component: viewDescriptor.tag}, isAnimatedProps);
++ })
+ };
+ } else {
+ updateProps = (viewDescriptors, updates) => {
diff --git a/src/App.tsx b/src/App.tsx
index 1ce17ea095bd..21025d34a661 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -31,6 +31,7 @@ import {CurrentReportIDContextProvider} from './components/withCurrentReportID';
import {EnvironmentProvider} from './components/withEnvironment';
import {KeyboardStateProvider} from './components/withKeyboardState';
import {WindowDimensionsProvider} from './components/withWindowDimensions';
+import CONFIG from './CONFIG';
import Expensify from './Expensify';
import useDefaultDragAndDrop from './hooks/useDefaultDragAndDrop';
import {ReportIDsContextProvider} from './hooks/useReportIDs';
@@ -52,51 +53,56 @@ LogBox.ignoreLogs([
const fill = {flex: 1};
+const StrictModeWrapper = CONFIG.USE_REACT_STRICT_MODE ? React.StrictMode : ({children}: {children: React.ReactElement}) => children;
+
function App({url}: AppProps) {
useDefaultDragAndDrop();
OnyxUpdateManager();
+
return (
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/src/CONFIG.ts b/src/CONFIG.ts
index 9ed4242d7604..8800cc907588 100644
--- a/src/CONFIG.ts
+++ b/src/CONFIG.ts
@@ -96,4 +96,5 @@ export default {
IOS_CLIENT_ID: '921154746561-s3uqn2oe4m85tufi6mqflbfbuajrm2i3.apps.googleusercontent.com',
},
GCP_GEOLOCATION_API_KEY: googleGeolocationAPIKey,
+ USE_REACT_STRICT_MODE: true,
} as const;
diff --git a/src/setup/platformSetup/index.website.ts b/src/setup/platformSetup/index.website.ts
index 77c373957510..07917e0e6f65 100644
--- a/src/setup/platformSetup/index.website.ts
+++ b/src/setup/platformSetup/index.website.ts
@@ -53,7 +53,6 @@ const webUpdater = (): PlatformSpecificUpdater => ({
export default function () {
AppRegistry.runApplication(Config.APP_NAME, {
rootTag: document.getElementById('root'),
- mode: 'legacy',
});
// When app loads, get current version (production only)