Speed, Sass, and a Shiny New React

Issue number #7

30 April 2025
5 minute to read.





React Native 0.78: Less Mess, More Zest, Optimistic UI at Its Best

Happy belated Valentine’s Day! While you were out on a last ditch attempt to save your marriage, @dream-sports-labs, @cortinico, @huntie, @Abbondanzo, and @okwasniewski were busy cooking up a special gift for all of us: sharper Android assets, easier iOS integration, and the return of our beloved console logs (with a not-so-subtle catch).

Let’s just say your love life might still be rocky, but your React Native repo is in a much better place.

Supporting React 19

With React Native 0.78, we now have support for React 19 and a whole host of features—many of which most of us have no clue about: what they’re for, how they work, or how to use them.

They’ve dropped old baggage like propTypes, introduced a number of fresh hooks such as useOptimistic, useActionState, and debuted Actions that juggle your async processes without you writing a labyrinth of loading states.

Let’s break it down.


Actions

In React 19, Actions are a feature that streamline asynchronous operations, such as form submissions, by leveraging the useTransition hook (a hook that allows you to mark state updates as non-blocking, keeping the UI responsive by letting certain updates be deferred while higher-priority updates render first). With Actions, you can define a function to handle data updates—like submitting a form—and React automatically manages the pending state and error handling during the async process, keeping the UI responsive without blocking user interactions.

In contrast, the "after" scenario showcases how Actions paired with useTransition simplify this:

👉 React 19 Actions

useActionState

Just like useTransition manages async transitions without scattered isPending logic, useActionState wraps your Action into a streamlined hook. It handles form state, errors, and results, so you don’t manually track loading or success. Instead of calling startTransition, useActionState does it behind the scenes when you submit a form. If an error is thrown, it’s returned; otherwise, it stays null. This simplifies async logic, keeping UI updates smooth and forms clean.

👉 React 19 useActionState

useOptimistic

useOptimistic updates the UI instantly before the server responds, applying a temporary state update inside startTransition(). If the server confirms, the update stays; if it fails, React reverts it on the next state update.

React doesn’t track errors—it just assumes the optimistic update is temporary. If no new state arrives, the update sticks around until another UI update triggers cleanup. There’s no built-in timeout—React handles it when the next state change happens.

No more waiting around—React 19 keeps things smooth, even if your request fails.

👉 React 19 useOptimistic

use API

The use API allows components to read the result of an async resource (like a Promise) and rely on Suspense (a React component that delays rendering until an asynchronous resource resolves, like data fetching, showing a fallback UI) to handle loading states. If the resource is pending, React suspends the component. If it fails, React bubbles the error to an Error Boundary (An Error Boundary is a special React component that catches JavaScript errors in its child components, preventing the entire app from crashing by displaying a fallback UI instead).

With use, you simply pass a Promise, and Suspense + Error Boundaries manage loading and errors—no more isLoading booleans or manual state handling.

👉 React 19 use API

React Compiler

Tired of sprinkling useMemo around like you’re seasoning your code with salt and pepper? Enter the React Compiler—a build-time optimiser that automatically memoizes repetitive calculations, so your app runs smoother without manual tweaks.

Instead of manually adding memos, just install the Babel plugin, rebuild, and let the compiler handle performance optimisations for you (Babel is a JavaScript compiler that transpiles modern JS into older versions for browser compatibility, using plugins and presets to transform code before execution).

It’s important to note that babel-plugin-react-compiler should run first before other Babel plugins.

The compiler analyses component logic and injects memoization safely—like a supercharged linter that doesn’t just warn about slowdowns but fixes them by inserting useMemo, useCallback, or React.memo. It follows React’s Rules of Hooks, avoids risky optimizations, and adds zero runtime overhead. If a piece of code might break, it leaves it alone.

Now, watch your components get a “Memo ✨” tag in DevTools—React’s way of saying, “Don’t worry, I got this.”

👉 React Compiler

ForwardRef: Have You Heard the News That You’re Dead?

Meanwhile, passing a ref to your function components no longer requires that awkward ceremony called forwardRef. Now you can treat ref like a regular prop, which means less “did I do that right?” and more “I can’t believe it was ever more complicated than this.”

👉 ref as a prop

Rewinding Logs & Vector Gains

Opt-in Metro Log Streaming

Yes, log streamingthe process where your console.log calls are forwarded directly to your development terminalis back after just four weeks of being removed, of which it’s removal was covered in issue #6, so put away your pitchforks. For context, Metro is React Native’s default bundler and dev server, the tool that transforms and serves your JavaScript code during development. Previously, Metro would capture and display all your logs, saving you a trip to Chrome DevTools.

Now you can restore those logs with the new --client-logs flag. But don’t get too attached—this is offered as a “temporary courtesy” rather than a permanent change. So hey, maybe keep those pitchforks handy after all.

👉 Opt-in for JavaScript logs in Metro

Android XML Drawables

With React Native 0.78, support for Android XML drawables means you can now define a graphic once using XML—a vector format that describes shapes and colours mathematically, this change simplifies asset management, reduces APK size, and ensures better visual consistency across devices. Previously, you had to provide separate bitmap images (e.g., icon.png, icon@2x.png, icon@3x.png). This single XML file scales perfectly on any screen, keeping your icons crisp and saving you from juggling several image files. The system compiles these XML assets locally, so when you use the <Image /> component, XML resources are loaded and inflated off the main thread so you don’t drop any frames.

Keep in mind these are purely local, compiled assets—don’t expect to load them from a URL. Give them an explicit size (or they’ll stay invisible), and watch your APK shrink while your icons stay crisp as ever.

👉 Android XML Drawables

Brownfield, Expo & Beyond

Expo Support for React Native 0.78

Expo isn’t immediately updating its stable SDK for React Native 0.78. As of now, Expo SDK 52 supports RN 0.76 by default, with RN 0.77 available as an opt-in. RN 0.78 introduces significant changes—most notably the upgrade to React 19—which aren’t yet compatible with Expo’s stable release.

To provide early access to these updates, Expo has introduced RN 0.78 support via a canary version of the SDK. Canary releases are essentially previews of the latest code, pulled straight from Expo’s main branch before they’re production-ready. While they offer access to experimental features, they also come with potential bugs, breaking changes, or compatibility issues—so they’re best suited for development and testing rather than production.

If you want to experiment with React Native 0.78 and React 19, you can opt into the canary channel by:

Expo plans to release a stable SDK (Expo SDK 53) in Spring 2025, likely supporting React Native 0.79. Until then, if you’re eager to explore RN 0.78, the canary channel is the way to go.

👉 Expo Support for React Native 0.78

12% Faster Startup

Ever stare at a blank loading screen and wonder where your life went wrong? @mrousavy has a PR that shaves an extra 12% off your app’s startup time by disabling bundle compression on Android—allowing the OS to quickly map your JS bundle into memory (fancy word: mmap), rather than decompressing it first. The trade-off? Your APK might bulk up by a meg or two. But hey, if you’re shipping a 200MB app anyway, does an extra 1MB even matter?

Once that’s set, your RN code loads from memory in about 400ms—less time than it takes to regret your last Tinder match. For some folks, that’s a big morale boost.

👉 Full PR details

ReactNativeFactory for iOS

If you’ve ever tried to slip React Native into an existing iOS app, you know it can feel like coaxing a cat into a carrier. With RCTReactNativeFactory, it’s far less painful: you spin up React Native right inside a ViewController, no AppDelegate footwork required. It’s basically a self-contained mini-app you can conjure whenever you want.

Now your iOS dev can keep their precious Swift code, and your RN dev can focus on that sweet JS inside a single screen. Love, in this case, truly wins.

👉 ReactNativeFactory on iOS

Brainy Apps, Sorting That Snaps, and React Native’s 2024 Facts

Bolt + Expo: Less Code, More ‘Instant App’ Magic

Bolt is an AI-powered dev agent from StackBlitz, and it just got a cozy integration with Expo. Picture it like this: you show up at bolt.new, pick the Expo template, type in your request—“Build me a snazzy recipe app with categories and a page for user-submitted recipes”—and Bolt spins up a working React Native project in seconds. No rummaging around boilerplate or wrestling with navigation config at midnight.

What you get is a real Expo app, complete with screens and layouts that you can tweak or refine the way you want. It’s not totally “no code,” but it cuts down those initial setup chores into a fraction of the time. Even better, once Bolt ties directly into Expo Application Services (EAS), you’ll be able to build, submit, and deploy this AI-born app straight from the browser.

👉 AI-powered Bolt in Expo

React Native Sortables

If your app has a list you’d like to re-organise by dragging items around, say goodbye to hacking together gestures and janky animations. The react-native-sortables library offers a one-stop, oh-so-satisfying drag-and-drop experience. It’s like giving your UI Marie Kondo superpowers: one graceful swipe, and that dog photo is now front and centre.

Under the hood, the library uses Reanimated and Gesture Handler for performance so slick, you’ll start “accidentally” dragging everything just for the fun of it. It supports both grids and linear lists, along with auto-scrolling when you drag to the edge of the screen. No manual scroll triggers, no messy code.

Here’s a quick example of a 2-column grid:

By default, the items shuffle around with that sweet “lift and drop” animation your users already expect from modern UIs. It’s a simple approach, but one that can give your app that Pinterest-like polish without the paranoid existential meltdown you usually endure trying to handle gestures.

👉 React Native Sortables Docs

State of React Native 2024 — Survey Results

Thanks to @swmansion, we have the State of React Native 2024. The latest survey shows Expo continues to surge—over 70% of devs now rely on it, making version upgrades much smoother. Nearly 23% have moved to the New Architecture (Fabric + TurboModules), we covered the New Architecture in issue #3, citing speed gains but still waiting on broader library support. Meanwhile, debugging remains the top pain point, with devs clamouring for better error messages. Despite these challenges, 88% are optimistic about React Native’s future, applauding improvements in performance and tooling.

👉 State of React Native 2024

Before You Go: Boost it, Build it, Push it

React Native Boost

React Native Boost is an experimental Babel plugin that improves rendering performance by removing unnecessary JavaScript-based wrappers around native components. By optimising how React Native interacts with the underlying platform, it can achieve up to 50% faster mounting for components like Text and View, especially in text-heavy applications.

React Native components like Text and View aren’t directly native—they are actually JavaScript wrappers that call their native counterparts, such as TextNativeComponent and ViewNativeComponent. These wrappers handle edge cases, like nesting View inside Text, press-able text elements, and accessibility requirements.

However, in most cases, these wrappers aren’t needed and introduce runtime overhead. React Native Boost analyses your code’s Abstract Syntax Tree (AST) using a Babel plugin to determine where it can safely replace JavaScript-based components with their direct native equivalents.

1️⃣ Install the library

Use your preferred package manager to install React Native Boost (as a regular dependency, NOT a dev dependency):

2️⃣ (For Expo Users) Create a Babel Config

If you don’t already have a babel.config.js file, run:

3️⃣ Add the Babel Plugin

Modify your babel.config.js file to include React Native Boost:

4️⃣ Restart Metro with a Clean Cache

To apply the changes, restart your development server and clear the cache:

👉 React Native Boost

Nitro 0.23 — Nitro Views

The Nitro toolkit (by @mrousavy) has introduced Nitro Views, allowing Swift/Kotlin UI components to be embedded in React Native without manual bridging. By leveraging Fabric, Nitro Views enable native performance while behaving like first-class React components. This means smoother animations, reduced JS-to-native overhead, and easier integration of high-performance or platform-specific UI elements.

1️⃣ Define Your Component’s Props & Methods in TypeScript

Instead of writing a bridge, define your native component’s API using TypeScript interfaces:

This ensures type safety between JavaScript and native code while keeping interop simple.

2️⃣ Implement the Native Component in Swift/Kotlin

Once the props and methods are defined, the native component is implemented in Swift or Kotlin.

3️⃣ Use the Component in Your React Native Code

Once the native implementation is complete, the component can be imported and used like any other React Native component:

Nitro automatically handles the C++ and JNI glue code, eliminating the need for manual bridging. Since HybridViews function as HybridObjects, they can be passed around natively without additional configuration.

👉 Nitro 0.23 Release

QuickPush

A lightweight macOS tool for testing Expo push notifications—no more curl commands. Drop in your Expo push token, craft a test message, and watch it arrive on your device. Great for quickly verifying that your notifications look right before shipping that new chat or alert feature.

👉 QuickPush

The Hitchhiker’s Guide to React Native

Authored by Luke Farrell and edited by Friosn.

Heavily inspired by the Bytes JavaScript newsletter—one of our favourites for dev updates— instead, this newsletter is all about diving deeper into React Native and its ecosystem. We still recommend checking out Bytes though, because their meme game is strong: https://bytes.dev

If you’re enjoying this newsletter, why not help us grow? Share it with your friends, family, and even that one coworker who always “forgets” to update dependencies. Use this link: https://www.reactnativerewind.com/

The VaultHitchhiker's Guide
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Made with 👽 tech by Luke Farrell, Seyda and Friosn.
Take me back to the paradise city, where the grass is green and the girls are pretty, oh, won’t you please take me home…