diff --git a/README.md b/README.md index c10c954a18646..529d6cb0ccfdb 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ * [Contributing to Expensify](contributingGuides/CONTRIBUTING.md) * [Expensify Code of Conduct](CODE_OF_CONDUCT.md) * [Contributor License Agreement](contributingGuides/CLA.md) +* [React StrictMode](contributingGuides/STRICT_MODE.md) ---- diff --git a/contributingGuides/STRICT_MODE.md b/contributingGuides/STRICT_MODE.md new file mode 100644 index 0000000000000..dfe94ea2c3ba4 --- /dev/null +++ b/contributingGuides/STRICT_MODE.md @@ -0,0 +1,44 @@ +# Usage of react concurrent mode and StrictMode +## Concurrent react +This App is rendered using react concurrent mode, which is the direction that React seems to be moving. + +Concurrent mode enables a lot of new behaviours in react, most importantly renders can be interrupted by React, re-run or run more than once. This is supposed to make react more performant and webapps more responsive to user actions. + +Further reading: + - [What is Concurrent React](https://react.dev/blog/2022/03/29/react-v18#what-is-concurrent-react) + +## StrictMode +Because the previously described concurrent mode could potentially introduce new bugs in the code (related to parallel rendering) we are using ``. +This is a recommendation from React team as per react official docs. + +`` is a component that wraps the whole App in (or parts of App) and it runs extra checks and extra behaviors only in dev. So in essence this is a developer tool. + +### Temporarily disabling StrictMode for dev +Strict mode *by default always* wraps entire Expensify App component tree. This happens in `src/App.tsx`. + +However, it might happen you want to temporarily disable `StrictMode` when developing, to verify that your code behaves properly. + +To do that: + - go to `src/CONFIG.ts` + - set `USE_REACT_STRICT_MODE_IN_DEV` flag to `false` + +_Important note_: this ☝️flag is strictly for developers. It does not affect production builds of React. +StrictMode is supposed to always wrap your App regardless of environment, and it will simply do nothing when run on production react build. +Only use this flag for local development and testing, but do not make it depending on `NODE_ENV` or any other env vars. + +### Common StrictMode pitfalls + - every component will go through: `mount -> unmount -> mount` on first app render + - any code running inside `useEffect(() => {...}, [])` that would be expected to run once on initial render, will run twice, this might include initial api calls + +#### Example: How StrictMode Affects AuthScreen +In AuthScreen, we have a typical pattern where certain logic is executed during mounting and unmounting, this is what happen after a refresh: +- Mounting: it runs `ReconnectApp`. +- Unmounting: AuthScreen cleans up data. +- Re-mounting Due to StrictMode: This behavior will cause `OpenApp` to be executed on the new mount. + +Impact: This double execution could lead to unnecessary API calls or unexpected states. + +Sources: + - [StrictMode docs](https://react.dev/reference/react/StrictMode) + - [StrictMode recommended usage](https://react.dev/reference/react/StrictMode) + - [Original PR introducing this feature](https://github.com/Expensify/App/pull/42592) \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index 98b5d4afeb1d9..4de8269fb4414 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -54,7 +54,7 @@ LogBox.ignoreLogs([ const fill = {flex: 1}; -const StrictModeWrapper = CONFIG.USE_REACT_STRICT_MODE ? React.StrictMode : ({children}: {children: React.ReactElement}) => children; +const StrictModeWrapper = CONFIG.USE_REACT_STRICT_MODE_IN_DEV ? React.StrictMode : ({children}: {children: React.ReactElement}) => children; function App({url}: AppProps) { useDefaultDragAndDrop(); diff --git a/src/CONFIG.ts b/src/CONFIG.ts index 8800cc907588a..a1a72b86fadd6 100644 --- a/src/CONFIG.ts +++ b/src/CONFIG.ts @@ -96,5 +96,6 @@ export default { IOS_CLIENT_ID: '921154746561-s3uqn2oe4m85tufi6mqflbfbuajrm2i3.apps.googleusercontent.com', }, GCP_GEOLOCATION_API_KEY: googleGeolocationAPIKey, - USE_REACT_STRICT_MODE: true, + // to read more about StrictMode see: contributingGuides/STRICT_MODE.md + USE_REACT_STRICT_MODE_IN_DEV: true, } as const;