weshipit.today — React Native Newsletter — 2026-W17
Week of April 20–April 26, 2026
Items This Week
| # | Title | Label | Link |
|---|---|---|---|
| 1 | VisionCamera v5 — Full Nitro Modules Rewrite + Worklets Integration | 🟦 RN | Read |
| 2 | How Hipcamp Upgraded Expo SDK Versions with Claude Code | 🟧 EXPO | Read |
| 3 | Voltra 1.4 — Android Home-Screen Widgets + Ongoing Notifications | 🟦 RN | Read |
| 4 | A Guide to React Compiler Rendering (React Miami) | ⚛️ REACT | Read |
| 5 | Building Non-Blocking UIs with useTransition and useActionState | ⚛️ REACT | Read |
| 6 | React Email 6.0 — Now an Open-Source Email Editor Too | ⚛️ REACT | Read |
| 7 | Expo Sign in with GitHub | 🟧 EXPO | Read |
| 8 | Seth Webster (former Head of React at Meta) Joined Expo | 🟧 EXPO | Read |
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-camerav4 and install v5 - Update
package.jsonwithreact-native-vision-camera@^5and peerreact-native-worklets - Migrate
useFrameProcessorcalls to the new Worklets-based API (useWorklet) - Update camera permission declarations in
AndroidManifest.xmlandInfo.plistif 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-workletsmust be installed (replacesreact-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— bumpreact-native-vision-camerato^5.0.0, addreact-native-workletsios/Podfile— runpod installafter dependency updateandroid/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:
yarn remove react-native-vision-camera react-native-worklets-coreyarn add react-native-vision-camera@^5 react-native-worklets- Run
npx pod-install - Search codebase for all
useFrameProcessorusages and refactor touseWorkletpattern per the v5 migration guide: https://react-native-vision-camera.com/docs/guides/migrating-from-v4 - Update any frame processor plugins: each must export a Nitro Module compatible interface
- Build for iOS:
npx expo run:ios --device - Build for Android:
npx expo run:android --device - Manually test: open camera screen, take a photo, record a 5s video, run a frame processor
Acceptance criteria checklist:
-
react-native-vision-camerav5.x inpackage.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
🟧 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.jsonpresent) - Claude Code installed locally (
npm install -g @anthropic-ai/claude-code) - A
previewbuild profile ineas.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:
- Install Claude Code:
npm install -g @anthropic-ai/claude-code - Create
.claude/commands/upgrade-dependency.mdwith 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
- 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" - Review the audit output manually — confirm recommended actions
- For each of the top 5 critical packages:
claude /upgrade-dependency <package-name> - Review each generated PR, verify the EAS build link is green
Acceptance criteria checklist:
-
scripts/audit-dependencies.mdfile 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
⚛️ 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
isLoadingbooleans withuseTransition'sisPendingflag - Replace ad-hoc form state management with
useActionStatefor 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 instartTransitionscreens/ProfileFormScreen.tsx(or equivalent) — replace form state withuseActionStatescreens/DashboardScreen.tsx(or equivalent) — wrap data refresh inuseTransitioncomponents/LoadingOverlay.tsx— update to acceptisPendingprop instead ofisLoading
Step-by-step instructions:
- In each target screen, import
useTransitionanduseActionStatefromreact - 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();
});
};
- For forms, use
useActionState:
const [state, formAction, isPending] = useActionState(async (prev, formData) => {
return await submitForm(formData);
}, null);
- Pass
isPendingto loading indicators instead of managingisLoadingmanually - 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
🟦 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.0and 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— addvoltra@^1.4.0app.json/app.config.ts— register the Voltra Expo config pluginwidgets/StatsWidget.tsx— new widget componentsrc/services/widgetService.ts— helper to callupdateWidget()
Step-by-step instructions:
yarn add voltra@^1.4.0- Add the plugin to
app.config.ts:
plugins: [
['voltra', { android: { widgets: ['StatsWidget'] } }]
]
- 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>
);
}
- Register the widget in
voltra.config.ts(root of project) - Update widget data from the app:
import { updateWidget } from 'voltra';
await updateWidget('StatsWidget', { count: 42 });
- Run
eas build --platform android --profile preview - 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
⚛️ 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-compilerand configure it inbabel.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/useCallbackcalls (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-compileris installed and configured inbabel.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— addbabel-plugin-react-compilerandeslint-plugin-react-compilerbabel.config.js— configure the compiler plugineslint.config.js/.eslintrc.js— add the React Compiler ESLint plugincomponents/ProductList.tsx,components/UserCard.tsx,screens/HomeScreen.tsx— add'use memo'directive
Step-by-step instructions:
- Install dependencies:
yarn add -D babel-plugin-react-compiler eslint-plugin-react-compiler
- Configure Babel (
babel.config.js):
module.exports = {
presets: ['babel-preset-expo'],
plugins: [
['babel-plugin-react-compiler', {
compilationMode: 'annotation',
target: '19',
}],
],
};
- 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' } }
];
- Annotate your most-rendered components:
function ProductList({ items }) {
'use memo';
return <FlatList data={items} renderItem={...} />;
}
- Run ESLint:
yarn eslint components/ProductList.tsx— fix any reported violations - Run your test suite:
yarn test - Start the app:
npx expo start --clear— check no new warnings in the console
Acceptance criteria checklist:
-
babel-plugin-react-compilerpresent inpackage.jsondevDependencies -
babel.config.jsincludes the plugin withcompilationMode: '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
Last update on April 27, 2026