Upgrade React Native Fixture App
Overview
The fixture app lives in fixture/react-native/. It is the primary test vehicle for FlashList on iOS and Android. The web fixture (fixture/web/) uses Expo and is independent — check it builds after the upgrade but it does not need the same dependency changes.
Step 1 — Research the Target Version
Check the latest stable RN version:
npm view react-native@latest version
Use the rn-diff-purge repo to see the exact template diff between your current and target version:
https://raw.githubusercontent.com/react-native-community/rn-diff-purge/release/<version>/RnDiffApp/<file>
Key files to fetch:
package.json — React version, CLI versions, dev dep versions
android/build.gradle — SDK versions, Kotlin version
android/app/build.gradle — plugin names, dependency patterns
android/gradle.properties — feature flags (newArch, hermes, edgeToEdge)
android/gradle/wrapper/gradle-wrapper.properties — Gradle version
android/settings.gradle — plugin management pattern
android/app/src/main/java/com/rndiffapp/MainApplication.kt — app initialization pattern
ios/Podfile — pod configuration, post_install hooks
ios/RnDiffApp/AppDelegate.swift — app delegate pattern
metro.config.js — Metro config API changes
Check third-party library compatibility with the target RN version:
react-native-reanimated — check compatibility table
react-native-gesture-handler — supports 3 latest RN minors
react-native-screens, react-native-safe-area-context — usually latest works
@react-navigation/* — check for breaking changes
- Any image library (
@d11/react-native-fast-image, etc.)
Step 2 — Update Dependencies
fixture/react-native/package.json
Update in this order:
react and react-native — match the template
@react-native/* dev packages — must match the RN minor (e.g., @react-native/babel-preset@0.84.1 for RN 0.84.1)
@react-native-community/cli* — match the template
- Third-party native libraries — bump to versions compatible with the target RN
- Any new peer dependencies (e.g., reanimated 4 requires
react-native-worklets)
Babel config
Check if any Babel plugins moved packages. Example: reanimated 4 moved react-native-reanimated/plugin to react-native-worklets/plugin.
Metro config
Metro's internal module paths change between versions. Common breakage:
metro-config/src/defaults/exclusionList — in newer Metro this moved to metro-config/private/defaults/exclusionList and exports a .default instead of a direct function
- Always verify the import works:
node -e "console.log(typeof require('<path>'))"
Step 3 — Update Android
android/build.gradle
buildToolsVersion, compileSdkVersion, targetSdkVersion — match template
kotlinVersion — match template
ndkVersion — match template (usually unchanged between minors)
android/gradle/wrapper/gradle-wrapper.properties
- Update Gradle distribution URL to match template
android/gradle.properties
- Remove deprecated flags (e.g.,
android.enableJetifier, FLIPPER_VERSION)
- Add new flags (e.g.,
edgeToEdgeEnabled)
- Update JVM args if template changed them
android/app/build.gradle
- Update plugin names if changed (e.g.,
kotlin-android → org.jetbrains.kotlin.android)
- Remove unused imports (e.g.,
import com.android.build.OutputFile)
- Check
autolinkLibrariesWithApp() is present
android/settings.gradle
- Match template structure
- Remove manual project includes for pure-JS libraries (flash-list has no native Android code)
MainApplication.kt
- This changes significantly between major RN versions. Always diff against the template.
- Preserve custom code:
AppPackage() registration and I18nUtil.allowRTL() for RTL support.
- Key pattern changes across versions:
- 0.79:
SoLoader.init() + DefaultNewArchitectureEntryPoint.load() + ReactNativeHost
- 0.84:
loadReactNative(this) + getDefaultReactHost() with lazy delegate (no ReactNativeHost)
Step 4 — Update iOS
ios/Podfile
- Match template structure
- Remove deprecated env vars (e.g.,
ENV['RCT_NEW_ARCH_ENABLED'] when new arch is the default)
- Remove deprecated helper calls (e.g.,
get_default_flags())
- Keep project-specific customizations (
use_frameworks! :linkage => :static if needed)
ios/FlatListPro.xcodeproj/project.pbxproj
- Update
IPHONEOS_DEPLOYMENT_TARGET to match the RN minimum (e.g., 15.1 for RN 0.76+)
- Pod install will update header search paths and build settings automatically
ios/FlatListPro/Info.plist
- Add any new required plist keys (e.g.,
RCTNewArchEnabled)
Clean install
cd fixture/react-native
rm -rf node_modules yarn.lock
yarn install
cd ios && rm -rf Pods Podfile.lock && pod install && cd ..
Step 5 — Build and Verify
Build the flash-list library first
yarn build # from repo root — compiles src/ → dist/
iOS
cd fixture/react-native
xcodebuild -workspace ios/FlatListPro.xcworkspace -scheme FlatListPro \
-configuration Debug -sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone 16 Pro' build
Android
cd fixture/react-native
yarn react-native run-android
Web
cd fixture/web && yarn install && npx expo export --platform web
Step 6 — Run Tests
Unit tests
yarn test # from repo root — 181+ tests must pass
E2E tests (iOS)
cd fixture/react-native
yarn e2e:build:ios
yarn e2e:test:ios
Screenshot reference updates: Visual diff tests (e.g., Carousel orientation) will fail after an RN upgrade because rendering changes slightly. To regenerate references:
- Delete the old reference directory (e.g.,
e2e/artifacts/ios/Carousel_landscape/)
- Run the test — it creates a new reference and fails with "no reference present"
- Run again — it passes using the new reference
- Repeat for each failing screenshot (the test stops at the first missing reference per run)
Common Pitfalls
- Metro
exclusionList import — Metro's internal API paths change between versions. Always verify the import resolves before starting Metro.
- Stale Metro on wrong port — Kill ALL Metro instances before testing. Another project's Metro on a different port can cause "version mismatch" errors if the app connects to it.
react-native-reanimated major version — Major bumps (3→4) require Babel plugin changes and may add new peer dependencies (react-native-worklets).
- Gradle version jumps — RN upgrades often bump Gradle (e.g., 8.x→9.x). This can break custom Gradle scripts. Check build warnings for deprecations.
IPHONEOS_DEPLOYMENT_TARGET — Must match or exceed the RN minimum. Pod install updates most settings, but the project-level target in pbxproj must be set manually.
Info.plist new keys — Some RN versions require new plist entries (e.g., RCTNewArchEnabled). Check the template's Info.plist diff.
- Legacy arch removal — Starting with RN 0.82+, legacy architecture code is being removed. Ensure all dependencies support new arch.
1---2name: upgrade-react-native3description: Upgrade the React Native fixture app to a new version. Covers JS deps, Android (Gradle, Kotlin, SDK), iOS (Podfile, pbxproj), Metro config, and third-party libraries.4---56# Upgrade React Native Fixture App78## Overview910The fixture app lives in `fixture/react-native/`. It is the primary test vehicle for FlashList on iOS and Android. The web fixture (`fixture/web/`) uses Expo and is independent — check it builds after the upgrade but it does not need the same dependency changes.1112## Step 1 — Research the Target Version13141. Check the latest stable RN version:15 ```bash16 npm view react-native@latest version17 ```18192. Use the **rn-diff-purge** repo to see the exact template diff between your current and target version:20 ```21 https://raw.githubusercontent.com/react-native-community/rn-diff-purge/release/<version>/RnDiffApp/<file>22 ```23 Key files to fetch:24 - `package.json` — React version, CLI versions, dev dep versions25 - `android/build.gradle` — SDK versions, Kotlin version26 - `android/app/build.gradle` — plugin names, dependency patterns27 - `android/gradle.properties` — feature flags (newArch, hermes, edgeToEdge)28 - `android/gradle/wrapper/gradle-wrapper.properties` — Gradle version29 - `android/settings.gradle` — plugin management pattern30 - `android/app/src/main/java/com/rndiffapp/MainApplication.kt` — app initialization pattern31 - `ios/Podfile` — pod configuration, post_install hooks32 - `ios/RnDiffApp/AppDelegate.swift` — app delegate pattern33 - `metro.config.js` — Metro config API changes34353. Check **third-party library compatibility** with the target RN version:36 - `react-native-reanimated` — check [compatibility table](https://docs.swmansion.com/react-native-reanimated/docs/guides/compatibility/)37 - `react-native-gesture-handler` — supports 3 latest RN minors38 - `react-native-screens`, `react-native-safe-area-context` — usually latest works39 - `@react-navigation/*` — check for breaking changes40 - Any image library (`@d11/react-native-fast-image`, etc.)4142## Step 2 — Update Dependencies4344### `fixture/react-native/package.json`4546Update in this order:471. `react` and `react-native` — match the template482. `@react-native/*` dev packages — must match the RN minor (e.g., `@react-native/babel-preset@0.84.1` for RN 0.84.1)493. `@react-native-community/cli*` — match the template504. Third-party native libraries — bump to versions compatible with the target RN515. Any new peer dependencies (e.g., reanimated 4 requires `react-native-worklets`)5253### Babel config5455Check if any Babel plugins moved packages. Example: reanimated 4 moved `react-native-reanimated/plugin` to `react-native-worklets/plugin`.5657### Metro config5859Metro's internal module paths change between versions. Common breakage:60- `metro-config/src/defaults/exclusionList` — in newer Metro this moved to `metro-config/private/defaults/exclusionList` and exports a `.default` instead of a direct function61- Always verify the import works: `node -e "console.log(typeof require('<path>'))"`6263## Step 3 — Update Android6465### `android/build.gradle`66- `buildToolsVersion`, `compileSdkVersion`, `targetSdkVersion` — match template67- `kotlinVersion` — match template68- `ndkVersion` — match template (usually unchanged between minors)6970### `android/gradle/wrapper/gradle-wrapper.properties`71- Update Gradle distribution URL to match template7273### `android/gradle.properties`74- Remove deprecated flags (e.g., `android.enableJetifier`, `FLIPPER_VERSION`)75- Add new flags (e.g., `edgeToEdgeEnabled`)76- Update JVM args if template changed them7778### `android/app/build.gradle`79- Update plugin names if changed (e.g., `kotlin-android` → `org.jetbrains.kotlin.android`)80- Remove unused imports (e.g., `import com.android.build.OutputFile`)81- Check `autolinkLibrariesWithApp()` is present8283### `android/settings.gradle`84- Match template structure85- Remove manual project includes for pure-JS libraries (flash-list has no native Android code)8687### `MainApplication.kt`88- **This changes significantly between major RN versions.** Always diff against the template.89- Preserve custom code: `AppPackage()` registration and `I18nUtil.allowRTL()` for RTL support.90- Key pattern changes across versions:91 - 0.79: `SoLoader.init()` + `DefaultNewArchitectureEntryPoint.load()` + `ReactNativeHost`92 - 0.84: `loadReactNative(this)` + `getDefaultReactHost()` with lazy delegate (no ReactNativeHost)9394## Step 4 — Update iOS9596### `ios/Podfile`97- Match template structure98- Remove deprecated env vars (e.g., `ENV['RCT_NEW_ARCH_ENABLED']` when new arch is the default)99- Remove deprecated helper calls (e.g., `get_default_flags()`)100- Keep project-specific customizations (`use_frameworks! :linkage => :static` if needed)101102### `ios/FlatListPro.xcodeproj/project.pbxproj`103- Update `IPHONEOS_DEPLOYMENT_TARGET` to match the RN minimum (e.g., 15.1 for RN 0.76+)104- Pod install will update header search paths and build settings automatically105106### `ios/FlatListPro/Info.plist`107- Add any new required plist keys (e.g., `RCTNewArchEnabled`)108109### Clean install110```bash111cd fixture/react-native112rm -rf node_modules yarn.lock113yarn install114cd ios && rm -rf Pods Podfile.lock && pod install && cd ..115```116117## Step 5 — Build and Verify118119### Build the flash-list library first120```bash121yarn build # from repo root — compiles src/ → dist/122```123124### iOS125```bash126cd fixture/react-native127xcodebuild -workspace ios/FlatListPro.xcworkspace -scheme FlatListPro \128 -configuration Debug -sdk iphonesimulator \129 -destination 'platform=iOS Simulator,name=iPhone 16 Pro' build130```131132### Android133```bash134cd fixture/react-native135yarn react-native run-android136```137138### Web139```bash140cd fixture/web && yarn install && npx expo export --platform web141```142143## Step 6 — Run Tests144145### Unit tests146```bash147yarn test # from repo root — 181+ tests must pass148```149150### E2E tests (iOS)151```bash152cd fixture/react-native153yarn e2e:build:ios154yarn e2e:test:ios155```156157**Screenshot reference updates**: Visual diff tests (e.g., Carousel orientation) will fail after an RN upgrade because rendering changes slightly. To regenerate references:1581. Delete the old reference directory (e.g., `e2e/artifacts/ios/Carousel_landscape/`)1592. Run the test — it creates a new reference and fails with "no reference present"1603. Run again — it passes using the new reference1614. Repeat for each failing screenshot (the test stops at the first missing reference per run)162163## Common Pitfalls164165- **Metro `exclusionList` import** — Metro's internal API paths change between versions. Always verify the import resolves before starting Metro.166- **Stale Metro on wrong port** — Kill ALL Metro instances before testing. Another project's Metro on a different port can cause "version mismatch" errors if the app connects to it.167- **`react-native-reanimated` major version** — Major bumps (3→4) require Babel plugin changes and may add new peer dependencies (`react-native-worklets`).168- **Gradle version jumps** — RN upgrades often bump Gradle (e.g., 8.x→9.x). This can break custom Gradle scripts. Check build warnings for deprecations.169- **`IPHONEOS_DEPLOYMENT_TARGET`** — Must match or exceed the RN minimum. Pod install updates most settings, but the project-level target in pbxproj must be set manually.170- **`Info.plist` new keys** — Some RN versions require new plist entries (e.g., `RCTNewArchEnabled`). Check the template's Info.plist diff.171- **Legacy arch removal** — Starting with RN 0.82+, legacy architecture code is being removed. Ensure all dependencies support new arch.