weshipit.today — React Native Newsletter — 2026-W17

Week of April 20–April 26, 2026

Items This Week

#TitleLabelLink
1VisionCamera v5 — Full Nitro Modules Rewrite + Worklets Integration🟦 RNRead
2How Hipcamp Upgraded Expo SDK Versions with Claude Code🟧 EXPORead
3Voltra 1.4 — Android Home-Screen Widgets + Ongoing Notifications🟦 RNRead
4A Guide to React Compiler Rendering (React Miami)⚛️ REACTRead
5Building Non-Blocking UIs with useTransition and useActionState⚛️ REACTRead
6React Email 6.0 — Now an Open-Source Email Editor Too⚛️ REACTRead
7Expo Sign in with GitHub🟧 EXPORead
8Seth Webster (former Head of React at Meta) Joined Expo🟧 EXPORead

5-Day Action Plan


🟦 Chunk 1 — Migrate Camera to VisionCamera v5 (Nitro Modules)

Goal: Upgrade the app's camera integration to VisionCamera v5, benefitting from the full Nitro Modules rewrite for near-zero JSI overhead, native Worklets support, and the new modular plugin architecture — delivering a faster and more reliable camera experience to end users.

Scope:

  • Uninstall react-native-vision-camera v4 and install v5
  • Update package.json with react-native-vision-camera@^5 and peer react-native-worklets
  • Migrate useFrameProcessor calls to the new Worklets-based API (useWorklet)
  • Update camera permission declarations in AndroidManifest.xml and Info.plist if changed
  • Validate all existing frame processor plugins against the new modular plugin architecture
  • Run a full build on iOS and Android to confirm no native compilation errors
  • Smoke-test record, photo capture, and frame processor pipeline on a real device

Out of scope:

  • Adding new camera features (zoom controls, HDR, etc.)
  • Migrating to new pro controls (ProCamera, manual exposure)
  • Updating CI/CD pipelines

Dependencies:

  • react-native-worklets must be installed (replaces react-native-worklets-core)
  • Existing frame processor plugins must individually support Nitro Modules (check each repo)

Acceptance criteria:

  • Camera preview renders correctly on both iOS and Android
  • Photo capture and video recording work end-to-end
  • No native build errors or JS runtime exceptions in the frame processor pipeline
  • App passes existing camera-related tests (unit + e2e smoke test)

Estimated effort: M

<details> <summary>**Copy/paste this prompt:**</summary>

Implement the following React Native chunk for your mobile app:

Goal: Upgrade react-native-vision-camera from v4 to v5 (Nitro Modules rewrite).

Files to create or modify:

  • package.json — bump react-native-vision-camera to ^5.0.0, add react-native-worklets
  • ios/Podfile — run pod install after dependency update
  • android/app/build.gradle — verify minSdkVersion compatibility
  • All files importing useFrameProcessor — migrate to the new Worklets API
  • Info.plist / AndroidManifest.xml — verify permission keys haven't changed

Step-by-step instructions:

  1. yarn remove react-native-vision-camera react-native-worklets-core
  2. yarn add react-native-vision-camera@^5 react-native-worklets
  3. Run npx pod-install
  4. Search codebase for all useFrameProcessor usages and refactor to useWorklet pattern per the v5 migration guide: https://react-native-vision-camera.com/docs/guides/migrating-from-v4
  5. Update any frame processor plugins: each must export a Nitro Module compatible interface
  6. Build for iOS: npx expo run:ios --device
  7. Build for Android: npx expo run:android --device
  8. Manually test: open camera screen, take a photo, record a 5s video, run a frame processor

Acceptance criteria checklist:

  • react-native-vision-camera v5.x in package.json
  • No TypeScript compile errors
  • Camera preview renders on both platforms
  • Photo capture saves correctly to the camera roll
  • Video recording produces a valid file
  • Frame processor runs without crashing
</details>

🟧 Chunk 2 — Automate Expo SDK Upgrade with Claude Code Agent

Goal: Reduce the time and risk of upgrading Expo SDK versions by setting up a structured AI-assisted upgrade workflow (inspired by Hipcamp's experience going from 2–3 months to a single sprint), enabling the team to stay current with Expo releases without derailing feature work.

Scope:

  • Audit all dependencies against New Architecture compatibility using a Claude Code prompt
  • Generate a dependency upgrade plan (markdown checklist: upgrade / replace / remove)
  • Create per-dependency EAS Build validation scripts
  • Run Claude Code on the top 5 most critical outdated dependencies and open one PR per dependency
  • Validate each PR builds successfully with eas build --platform all --profile preview

Out of scope:

  • Full New Architecture migration (separate chunk)
  • Upgrading all 40+ dependencies in one session
  • Writing new tests for migrated dependencies

Dependencies:

  • EAS CLI authenticated and configured (eas.json present)
  • Claude Code installed locally (npm install -g @anthropic-ai/claude-code)
  • A preview build profile in eas.json

Acceptance criteria:

  • Dependency audit document exists (markdown) listing every outdated package with a recommended action
  • At least 5 dependency upgrade PRs exist, each with an EAS Build link proving successful build
  • No regressions on the main branch

Estimated effort: M

<details> <summary>**Copy/paste this prompt:**</summary>

Implement the following React Native chunk for your mobile app:

Goal: Set up and execute an AI-assisted Expo SDK upgrade workflow using Claude Code.

Files to create or modify:

  • scripts/audit-dependencies.md — output file for dependency audit
  • .claude/commands/upgrade-dependency.md — custom Claude Code slash command

Step-by-step instructions:

  1. Install Claude Code: npm install -g @anthropic-ai/claude-code
  2. Create .claude/commands/upgrade-dependency.md with this content:
Upgrade the dependency $ARGUMENTS to its latest New Architecture-compatible version.
Steps:
1. Check the package's GitHub releases and CHANGELOG for breaking changes
2. Check https://reactnative.directory to confirm New Architecture support
3. Prefer Expo equivalents (expo-*, @expo/*) if available
4. Update package.json, run yarn install, fix any TypeScript errors
5. Run: npx expo prebuild --clean, then eas build --platform all --profile preview
6. Create a PR with: the EAS build link, migration notes, affected screens
  1. Run the audit: claude "List all dependencies in package.json that do not support React Native New Architecture. Output a markdown table with columns: package, current version, latest version, new-arch support (yes/no/unknown), recommended action (upgrade/replace/remove). Save to scripts/audit-dependencies.md"
  2. Review the audit output manually — confirm recommended actions
  3. For each of the top 5 critical packages: claude /upgrade-dependency <package-name>
  4. Review each generated PR, verify the EAS build link is green

Acceptance criteria checklist:

  • scripts/audit-dependencies.md file exists and lists all outdated packages
  • At least 5 upgrade PRs created with EAS build links
  • All 5 EAS builds are green (no build errors)
  • No TypeScript errors on main branch after merges
</details>

⚛️ Chunk 3 — Implement Non-Blocking UI Flows with useTransition + useActionState

Goal: Improve perceived performance and responsiveness in forms and data-loading screens by adopting React's useTransition and useActionState hooks — ensuring the UI never freezes during async operations and users always get immediate feedback.

Scope:

  • Identify the top 3 screens with blocking async interactions (e.g. form submission, data refresh, search)
  • Refactor each screen to wrap the async handler in startTransition
  • Replace local isLoading booleans with useTransition's isPending flag
  • Replace ad-hoc form state management with useActionState for form-driven screens
  • Add skeleton or spinner states driven by isPending
  • Verify UI stays interactive (scrollable, tappable) during the transition

Out of scope:

  • Server Actions or RSC (React Server Components)
  • Global state management refactor
  • New screens or features

Dependencies:

  • React 19+ (ships with Expo SDK 54+)
  • No external libraries required

Acceptance criteria:

  • On the 3 selected screens, tapping "Submit" / "Refresh" never causes a UI freeze
  • A loading indicator appears within 100ms of the user action
  • The rest of the UI remains interactive during the async transition
  • No regression in existing navigation or state behavior

Estimated effort: S

<details> <summary>**Copy/paste this prompt:**</summary>

Implement the following React Native chunk for your mobile app:

Goal: Refactor async UI interactions using useTransition and useActionState to prevent blocking the UI thread.

Files to create or modify:

  • screens/SearchScreen.tsx (or equivalent) — wrap search fetch in startTransition
  • screens/ProfileFormScreen.tsx (or equivalent) — replace form state with useActionState
  • screens/DashboardScreen.tsx (or equivalent) — wrap data refresh in useTransition
  • components/LoadingOverlay.tsx — update to accept isPending prop instead of isLoading

Step-by-step instructions:

  1. In each target screen, import useTransition and useActionState from react
  2. Replace const [isLoading, setIsLoading] = useState(false) patterns:
// BEFORE
const [isLoading, setIsLoading] = useState(false);
const handleSubmit = async () => {
  setIsLoading(true);
  await saveData();
  setIsLoading(false);
};

// AFTER
const [isPending, startTransition] = useTransition();
const handleSubmit = () => {
  startTransition(async () => {
    await saveData();
  });
};
  1. For forms, use useActionState:
const [state, formAction, isPending] = useActionState(async (prev, formData) => {
  return await submitForm(formData);
}, null);
  1. Pass isPending to loading indicators instead of managing isLoading manually
  2. Test on a slow network (throttle to 3G in dev) to confirm UI stays responsive

Acceptance criteria checklist:

  • No useState(false) loading boolean anti-pattern remains in the 3 target screens
  • UI remains scrollable/tappable while async operation is in progress
  • Loading indicator appears immediately on action trigger
  • No TypeScript errors
  • Tested manually on a throttled network connection
</details>

🟦 Chunk 4 — Add Android Home-Screen Widgets with Voltra 1.4

Goal: Ship an Android home-screen widget for the app using Voltra 1.4, leveraging its new Material You dynamic color support so the widget automatically matches each user's wallpaper and system theme — increasing daily active engagement outside the app.

Scope:

  • Install voltra@^1.4.0 and configure the Expo config plugin
  • Design and implement one Android widget (e.g. a stats summary or quick-action widget) as a React component
  • Configure light/dark/dynamic Material You color theming for the widget
  • Test widget rendering on an Android emulator (API 31+) and a physical device
  • Verify widget updates when app data changes (via updateWidget())

Out of scope:

  • iOS Live Activities or Dynamic Island (separate chunk)
  • Android ongoing notifications (separate chunk)
  • More than one widget variant

Dependencies:

  • Expo SDK 54+ with New Architecture enabled
  • Android device/emulator running API 31+ (for Material You)
  • EAS Build for the native build (managed workflow)

Acceptance criteria:

  • Widget appears in the Android widget picker after install
  • Widget content renders correctly in light mode, dark mode, and with a dynamic wallpaper color
  • Widget data updates without requiring an app relaunch
  • EAS Build (Android) succeeds with the Voltra plugin configured

Estimated effort: M

<details> <summary>**Copy/paste this prompt:**</summary>

Implement the following React Native chunk for your mobile app:

Goal: Add an Android home-screen widget using Voltra 1.4 with Material You dynamic colors.

Files to create or modify:

  • package.json — add voltra@^1.4.0
  • app.json / app.config.ts — register the Voltra Expo config plugin
  • widgets/StatsWidget.tsx — new widget component
  • src/services/widgetService.ts — helper to call updateWidget()

Step-by-step instructions:

  1. yarn add voltra@^1.4.0
  2. Add the plugin to app.config.ts:
plugins: [
  ['voltra', { android: { widgets: ['StatsWidget'] } }]
]
  1. Create widgets/StatsWidget.tsx:
import { Widget, WidgetBackground, WidgetText } from 'voltra';
export default function StatsWidget() {
  return (
    <Widget>
      <WidgetBackground theme="materialYou" />
      <WidgetText style={{ fontSize: 16 }}>Today's Stats</WidgetText>
    </Widget>
  );
}
  1. Register the widget in voltra.config.ts (root of project)
  2. Update widget data from the app:
import { updateWidget } from 'voltra';
await updateWidget('StatsWidget', { count: 42 });
  1. Run eas build --platform android --profile preview
  2. Install the APK on a device, long-press the home screen, add the widget, verify it renders and updates

Acceptance criteria checklist:

  • Widget appears in the Android widget picker
  • Widget renders correctly in light mode
  • Widget renders correctly in dark mode
  • Widget colors adapt to wallpaper (Material You) on API 31+
  • updateWidget() call reflects new data without app relaunch
  • EAS Build succeeds
</details>

⚛️ Chunk 5 — Enable React Compiler in Your React Native App

Goal: Enable the React Compiler (formerly React Forget) in the app to automatically memoize components and hooks — eliminating manual useMemo/useCallback calls and improving runtime rendering performance without any behavior change for end users.

Scope:

  • Install babel-plugin-react-compiler and configure it in babel.config.js
  • Enable the compiler in opt-in mode (compilationMode: 'annotation') for safe incremental adoption
  • Annotate 3–5 performance-critical components with 'use memo' directive
  • Run the React Compiler ESLint plugin to identify violations in annotated components
  • Verify no regressions by running the existing test suite and a manual smoke test

Out of scope:

  • Enabling compiler globally across the entire codebase in one step
  • Removing all existing useMemo/useCallback calls (follow-up chunk)
  • Server Components

Dependencies:

  • React 19+ (Expo SDK 54+)
  • Babel configured (not SWC) — standard for React Native / Expo

Acceptance criteria:

  • babel-plugin-react-compiler is installed and configured in babel.config.js
  • At least 3 components successfully compile with the 'use memo' annotation
  • React Compiler ESLint plugin reports 0 errors on annotated components
  • All existing tests pass
  • App builds and runs without warnings about Rules of React violations

Estimated effort: S

<details> <summary>**Copy/paste this prompt:**</summary>

Implement the following React Native chunk for your mobile app:

Goal: Enable the React Compiler in opt-in mode for incremental adoption in a React Native / Expo project.

Files to create or modify:

  • package.json — add babel-plugin-react-compiler and eslint-plugin-react-compiler
  • babel.config.js — configure the compiler plugin
  • eslint.config.js / .eslintrc.js — add the React Compiler ESLint plugin
  • components/ProductList.tsx, components/UserCard.tsx, screens/HomeScreen.tsx — add 'use memo' directive

Step-by-step instructions:

  1. Install dependencies:
yarn add -D babel-plugin-react-compiler eslint-plugin-react-compiler
  1. Configure Babel (babel.config.js):
module.exports = {
  presets: ['babel-preset-expo'],
  plugins: [
    ['babel-plugin-react-compiler', {
      compilationMode: 'annotation',
      target: '19',
    }],
  ],
};
  1. Add ESLint plugin:
// eslint.config.js
import reactCompiler from 'eslint-plugin-react-compiler';
export default [
  { plugins: { 'react-compiler': reactCompiler },
    rules: { 'react-compiler/react-compiler': 'error' } }
];
  1. Annotate your most-rendered components:
function ProductList({ items }) {
  'use memo';
  return <FlatList data={items} renderItem={...} />;
}
  1. Run ESLint: yarn eslint components/ProductList.tsx — fix any reported violations
  2. Run your test suite: yarn test
  3. Start the app: npx expo start --clear — check no new warnings in the console

Acceptance criteria checklist:

  • babel-plugin-react-compiler present in package.json devDependencies
  • babel.config.js includes the plugin with compilationMode: 'annotation'
  • At least 3 components annotated with 'use memo'
  • ESLint reports 0 React Compiler errors on annotated files
  • All existing tests pass (yarn test)
  • App starts without React Rules violations in the console
</details>

Last update on April 27, 2026