weshipit.today — React Native Newsletter — 2026-W15

Week of April 6–April 12, 2026

Items This Week

#TitleLabelLink
1React Native 0.85 — New Animation Backend, Jest Preset, Metro TLS🟦 RNRead
2react-native-haptic-feedback 3.0🟦 RNRead
3React Native Skia 2.6🟦 RNRead
4The Uphill Climb of Making Diff Lines Performant on GitHub⚛️ REACTRead
5Moving Railway's Frontend Off Next.js (Vite + TanStack Router)⚛️ REACTRead
6React Status #469 — April 10, 2026⚛️ REACTRead

Sources: React Status #469 (Apr 10, 2026) · React Native Blog (Apr 7, 2026) · This Week In React (Apr 8, 2026) — newsletters tracked in the "Newsletters React Native" Notion database.


5-Day Action Plan


🟦 Chunk 1 — Upgrade to React Native 0.85

Goal: Bring the app to the latest stable React Native release, unblocking the new animation backend, eliminating deprecated APIs, and aligning with Node.js LTS versions — a prerequisite for every other chunk this week.

Scope:

  • Bump react-native to 0.85.x in package.json
  • Install @react-native/jest-preset and update jest.config.js (preset: '@react-native/jest-preset')
  • Search & replace all StyleSheet.absoluteFillObjectStyleSheet.absoluteFill
  • Migrate AccessibilityInfo.setAccessibilityFocusAccessibilityInfo.sendAccessibilityEvent
  • Verify CI runs on Node.js ≥ 20.19.4 (drop EOL v21/v23)
  • Smoke-test app boot on iOS simulator and Android emulator

Out of scope: Opting into the experimental New Animation Backend channel (0.85.1+), Expo SDK 56 upgrade, third-party library updates.

Dependencies: None — first chunk of the week.

Acceptance criteria:

  • npx react-native --version returns 0.85.x
  • All Jest tests pass with @react-native/jest-preset
  • Zero occurrences of absoluteFillObject in the codebase
  • App boots without crash on both iOS and Android
  • CI pipeline is green on a supported Node.js version

Estimated effort: M

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

Implement the following React Native chunk for your mobile app:

Goal: Upgrade the project to React Native 0.85.x.

Files to create or modify:

  • package.json — bump react-native to ^0.85.0
  • jest.config.js — replace preset: 'react-native' with preset: '@react-native/jest-preset'; add @react-native/jest-preset to devDependencies
  • Any file using StyleSheet.absoluteFillObject — replace with StyleSheet.absoluteFill
  • Any file calling AccessibilityInfo.setAccessibilityFocus — replace with AccessibilityInfo.sendAccessibilityEvent

Step-by-step instructions:

  1. Set "react-native": "0.85.0" in package.json and run npm install.
  2. In jest.config.js, install and reference @react-native/jest-preset.
  3. Search the codebase for absoluteFillObject — replace all occurrences.
  4. Search for setAccessibilityFocus — migrate to sendAccessibilityEvent.
  5. Run npx jest — fix any broken snapshots.
  6. Boot on iOS: npx react-native run-ios.
  7. Boot on Android: npx react-native run-android.

Acceptance criteria checklist:

  • react-native version is 0.85.x in node_modules
  • Jest runs with @react-native/jest-preset without errors
  • Zero absoluteFillObject occurrences remain
  • App launches on both platforms without crashes
  • No TypeScript errors on tsc --noEmit
</details>

🟦 Chunk 2 — Enable Native Driver on Layout Animations (New Animation Backend)

Goal: Deliver visibly smoother layout animations (Flexbox & position props) by opting into RN 0.85's Shared Animation Backend, eliminating JS-thread jank on expanding/collapsing UI elements.

Scope:

  • Opt in to the experimental channel (requires 0.85.1, available immediately after Chunk 1)
  • Identify 2–3 Animated.View components that animate layout props without native driver
  • Refactor those animations to use useNativeDriver: true on width, height, or flex
  • Verify 60 fps via the React Native Perf Monitor on a real or simulated device

Out of scope: Migrating to Reanimated 4, <ViewTransition> (not yet stable), or any new animation screens from scratch.

Dependencies: Chunk 1 (RN 0.85 must be installed; requires 0.85.1 patch for the experimental flag).

Acceptance criteria:

  • Layout animations run with useNativeDriver: true and no yellow warning
  • Perf Monitor shows UI thread at 60 fps during target animations
  • No JS thread drops visible in Systrace / Perf Monitor
  • Works correctly on both iOS and Android

Estimated effort: S

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

Implement the following React Native chunk for your mobile app:

Goal: Refactor existing layout animations to use useNativeDriver: true with the new Shared Animation Backend in React Native 0.85.

Files to create or modify:

  • Any component using Animated.timing / Animated.spring on width, height, top, left, or flex — add useNativeDriver: true
  • src/screens/AnimationDemo.tsx (create if absent) — demo expanding card

Step-by-step instructions:

  1. Follow https://reactnative.dev/docs/releases/release-levels to opt in to the experimental channel.
  2. Search the codebase for Animated.timing and Animated.spring calls.
  3. For any that animate layout props, add useNativeDriver: true.
  4. Create a demo screen:
const width = useAnimatedValue(100);
Animated.timing(width, { toValue: 300, duration: 500, useNativeDriver: true }).start();
<Animated.View style={{ width, height: 100, backgroundColor: 'blue' }} />
  1. Open Perf Monitor (shake → Perf Monitor) and confirm JS FPS stays at 60 during animation.

Acceptance criteria checklist:

  • useNativeDriver: true on all layout animations — no warnings
  • Perf Monitor UI thread at 60 fps during animation
  • Works on iOS and Android
  • No regressions in existing Reanimated-powered animations
</details>

🟦 Chunk 3 — Add Haptic Feedback to Key User Interactions

Goal: Improve perceived quality with contextual haptic feedback on primary actions (button presses, success confirmations, error states) — a zero-effort UX win that passes the "wow" test on physical devices.

Scope:

  • Install/upgrade react-native-haptic-feedback to v3.0
  • Create a useHaptics custom hook with typed trigger names
  • Wire haptics to: primary CTA buttons (impactMedium), success toasts (notificationSuccess), error banners (notificationError), pull-to-refresh release
  • Test on a physical iOS and Android device

Out of scope: Custom vibration patterns, audio feedback, haptics on web/Expo Go.

Dependencies: None — standalone library addition.

Acceptance criteria:

  • Library installs and links without breaking iOS or Android builds
  • Primary button press produces a tactile response on a physical device
  • Success and error haptics are contextually distinct
  • No crash on simulator (no haptic engine)

Estimated effort: S

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

Implement the following React Native chunk for your mobile app:

Goal: Add haptic feedback to key user interactions using react-native-haptic-feedback v3.0.

Files to create or modify:

  • package.json — add react-native-haptic-feedback@^3.0.0
  • src/hooks/useHaptics.ts — typed custom hook
  • src/components/PrimaryButton.tsx — trigger impactMedium on press
  • src/components/SuccessModal.tsx — trigger notificationSuccess on mount
  • src/components/ErrorBanner.tsx — trigger notificationError on mount

Step-by-step instructions:

  1. npm install react-native-haptic-feedback@^3.0.0 then cd ios && pod install.
  2. Create src/hooks/useHaptics.ts:
import ReactNativeHapticFeedback, { HapticFeedbackTypes } from 'react-native-haptic-feedback';
const options = { enableVibrateFallback: true, ignoreAndroidSystemSettings: false };
export function useHaptics() {
  return { trigger: (type: HapticFeedbackTypes) => ReactNativeHapticFeedback.trigger(type, options) };
}
  1. In PrimaryButton.tsx, call trigger('impactMedium') in the onPress handler.
  2. In success/error components, call the appropriate notification haptic on mount.

Acceptance criteria checklist:

  • Library links correctly on iOS and Android
  • useHaptics hook is typed and reusable
  • Primary button produces a tactile response on a physical device
  • Success and error haptics are distinct
  • No crash on simulator
</details>

⚛️ Chunk 4 — Audit & Fix useEffect Overuse in Performance-Critical Screens

Goal: Cut unnecessary re-renders and reduce interaction latency on the app's highest-traffic screens — directly applying lessons from GitHub's real-world React performance optimization case study.

Scope:

  • Profile 2–3 high-traffic screens with React DevTools Profiler (record a before baseline)
  • Identify useEffect calls replaceable by: useMemo, derived state, or direct event handlers
  • Refactor the identified anti-patterns one component at a time
  • Re-run the Profiler for an after baseline and document render count delta in the PR description

Out of scope: Full app performance audit, navigation layer changes, data-fetching architecture changes.

Dependencies: None — purely a refactor task.

Acceptance criteria:

  • Profiler shows measurably fewer renders on targeted screens (document the numbers)
  • No functional regressions — all existing tests pass
  • No useEffect with empty dependency arrays that compute a value (replaced with useMemo)
  • PR description includes before/after render counts per component

Estimated effort: M

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

Implement the following React Native chunk for your mobile app:

Goal: Audit and refactor useEffect overuse in performance-critical screens to reduce re-renders and improve interaction latency.

Files to create or modify:

  • The 2–3 most-visited screens in src/screens/ (e.g. HomeScreen.tsx, FeedScreen.tsx, ProfileScreen.tsx)
  • Any shared hooks these screens depend on

Step-by-step instructions:

  1. Open React DevTools Profiler. Record a typical user interaction on each target screen. Note render counts.
  2. Look for components that re-render more than twice per interaction.
  3. For each screen, find useEffect calls that:
    • Compute a derived value → replace with useMemo
    • Set state from props → replace with inline derived state
    • Could be a direct event handler → remove the effect
    • Have missing/wrong dependency arrays → fix the array
  4. Apply fixes one component at a time, re-running tests between each change.
  5. Re-record the Profiler. Document render counts in a PR comment.

Acceptance criteria checklist:

  • Profiler shows reduced render counts on targeted screens
  • No useEffect that only computes derived state remains
  • All Jest/RTL tests pass
  • No TypeScript errors
  • Before/after render counts documented in PR description
</details>

🟦 Chunk 5 — Configure Metro TLS for Secure Local Development

Goal: Enable HTTPS + WSS (Fast Refresh) on the Metro dev server so developers can test against APIs that require secure origins (OAuth, camera, geolocation, payment SDKs) without staging environment deployment.

Scope:

  • Install mkcert and generate a locally-trusted development certificate
  • Configure metro.config.js with the server.tls block
  • Verify Fast Refresh still works over WSS after the change
  • Document the full setup in README.md or docs/dev-setup.md
  • Add certificate files to .gitignore

Out of scope: Production TLS, CI/CD certificate automation, multi-developer certificate sharing.

Dependencies: Chunk 1 (Metro TLS requires RN 0.85).

Acceptance criteria:

  • Metro starts on https://localhost:8081 with no certificate warnings
  • Fast Refresh triggers correctly over WSS on file save
  • Other developers can reproduce the setup following the README
  • .gitignore excludes all generated certificate files

Estimated effort: S

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

Implement the following React Native chunk for your mobile app:

Goal: Configure Metro dev server with TLS so the app runs over HTTPS locally.

Files to create or modify:

  • metro.config.js — add config.server.tls block
  • README.md or docs/dev-setup.md — TLS setup instructions
  • .gitignore — exclude *.pem and *.key files

Step-by-step instructions:

  1. Install mkcert: brew install mkcert && mkcert -install.
  2. In the project root: mkcert localhost 127.0.0.1 ::1 → generates localhost+2.pem and localhost+2-key.pem.
  3. Add both files to .gitignore.
  4. Update metro.config.js:
const fs = require('fs');
config.server = {
  ...config.server,
  tls: {
    cert: fs.readFileSync('./localhost+2.pem'),
    key: fs.readFileSync('./localhost+2-key.pem'),
  },
};
  1. Run npx react-native start — confirm the URL starts with https://.
  2. Edit a file and confirm Fast Refresh triggers over wss://.
  3. Document steps 1–6 in README under "Local HTTPS Dev Server".

Acceptance criteria checklist:

  • Metro starts with https:// URL
  • No certificate warning in browser/DevTools
  • Fast Refresh works over WSS
  • .gitignore excludes certificate files
  • README documents the full setup
</details>

Last update on April 13, 2026