r/reactnative • • Apr 15 '26

Tutorial I just shipped my React Native app with expo, so here are the most 10 things - in my mind - that may be interesting to your next project

290 Upvotes

Hii,

So I recently published one of my React Native apps (finance/budgeting app, Expo-based) it's now on app store and has +1200 downloads, and wanted to share some of the tools and approaches that genuinely helped. Not the obvious stuff everyone already knows, but things I wish someone told me earlier.

1. react-native-keyboard-controller instead of KeyboardAvoidingView

If you've ever fought with the built-in KeyboardAvoidingView, just drop it. This library handles keyboard behavior properly on both platforms. Wrap your app with <KeyboardProvider> and forget about it. It also supports interactive keyboard dismiss (user drags the keyboard down) which feels super native.

2. react-native-draggable-flatlist with ScaleDecorator

Needed users to reorder their accounts and budgets by dragging. This library is basically a FlatList but draggable. The nice touch is wrapping each item in <ScaleDecorator>, it gives that satisfying little scale-up animation when you grab an item. Feels really polished with zero effort.

3. expo-speech-recognition for voice input

I wanted users to add transactions by voice ("spent 50 on coffee"). This package made it dead simple, one line to start, supports multiple languages, gives you interim results in real time. No need to mess with native modules or external APIs for the speech-to-text part.

4. expo-glass-effect for iOS 26 Liquid Glass

If you're on Expo SDK 54, you can use isLiquidGlassAvailable() to check if the device supports liquid glass and conditionally render native tabs vs your classic tab bar with BlurView. Your app looks modern on new devices and still works fine on older ones.

5. babel-plugin-react-compiler

Still in beta but already usable. It auto-memoizes your components and hooks at build time. I was manually writing useMemo and useCallback everywhere, now the compiler handles most of it. Just add it to your babel config and let it do its thing.

6. Receipt scanning with Gemini Vision API

This one was fun. User takes a photo of a receipt, I convert it to base64 and send it to Gemini as inline image data. The trick is asking it to extract individual line items, not just the total. So a grocery receipt becomes 5 separate transactions, each auto-categorized from the user's own category list. The prompt engineering matters a lot here, you have to be very specific about the output format or the AI gets creative.

7. Lottie for micro-interactions, not just onboarding

Everyone uses Lottie for splash screens and onboarding. I used it for tiny mood emojis on transactions, each mood (happy, stressed, neutral...) has a small 18x18 looping Lottie animation. Way more alive than static emoji. The key is keeping the JSON files small and using autoPlay loop.

8. @shopify/react-native-skia for animated mesh gradients

I wanted an animated gradient background (like the ones you see in modern fintech apps). Used Skia's shader support to write a custom GLSL mesh gradient that animates on the UI thread. The trick for performance is undersampling, render the shader at half resolution and scale it up. Users can't tell the difference and you save a ton of GPU work.

9. expo-haptics, but use the right feedback type

Don't just use one haptic style everywhere. There are different ones for a reason:

  • selectionAsync() for toggles and filter chips (light tap)
  • impactAsync(Medium) for button presses
  • impactAsync(Heavy) for destructive actions or long press
  • notificationAsync(Success) for confirmations

Small detail but users notice it subconsciously. Makes the whole app feel more "real".

10. Smooth number animations with Reanimated's useAnimatedReaction

For things like balance totals or chart values, I animate the number counting up/down instead of just snapping to the new value. The trick is using useAnimatedReaction to watch a shared value on the UI thread and push updates back to JS via runOnJS. You get a smooth 60fps counting effect without re-rendering your component on every frame. Works great for any kind of numeric display.

Also there's a thanks i want to say to the developer who created the open source lib https://www.reacticx.com/ i cloned some of its components in my app and it was looks sooo nice. if you guys has similar libraries like it just put it down in the comments.

Hope some of these help.

ai helped me to do some refinements to the ideas in this post.

r/reactnative • • Jul 13 '26

Tutorial I built a runtime that lets me update an installed React Native app without rebuilding it. Looking for developers to test whether this actually holds up.

24 Upvotes

A while ago, I started experimenting with an idea.

I wanted to see how much of a React Native application could be safely changed after the app was already built and installed, without having to rebuild the application and ship another binary for every supported change.

After a lot of work, I finally have the MVP running.

The video is a complete demonstration of the current workflow on a real Android device.

The application is built with a runtime that interprets a versioned schema. I can make supported changes to the application, commit them, and push a new version. The installed app receives the new schema and renders the changes without rebuilding or reinstalling the application.

This is not meant to replace normal app releases. Changes to native code, permissions, SDKs, or anything the installed runtime doesn't understand would still require a new build.

What I'm trying to explore is whether the parts of an application that change frequently can be maintained through a runtime instead of sending every change through the complete deployment pipeline.

So far, I've been the only person using it, which is obviously a problem. I built the system, so I already know how everything is supposed to work.

I need developers who haven't seen it before to use it and find the things I'm missing.

I'm looking for a few React Native developers who would be willing to actually try the MVP, build something small with it, and tell me where the experience breaks down. I'm not charging anything. I also don't expect anyone to move an existing production app onto an experimental runtime. I just want to see whether someone other than me can use this successfully and whether the idea is genuinely useful.

If you're interested in testing it, leave a comment and I'll reach out.

And even if you wouldn't use it, I'd still like to know what would stop you from trusting an architecture like this in a real application.

r/reactnative • • 17d ago

Tutorial How do you debug in React Native? I made a walkthrough of breakpoints, stepping and Watch in DevTools

7 Upvotes

I used to debug almost everything with console.log, and it cost me a lot of time. Once I started using breakpoints in React Native DevTools, finding bugs got much faster.

Here's the short version of what helped me:

- Breakpoints pause your app at an exact line, so you can inspect the real values at that moment instead of guessing which logs to add

- Stepping (step over / step into / step out) lets you follow the code line by line and see where it goes wrong

- Watch lets you track specific variables or expressions as the code runs, without adding a log for each one

- Different breakpoint types are useful in different situations, for example when a bug only happens under a certain condition

I recorded a video that explains why breakpoints are worth using and shows each of these live in React Native DevTools:

https://youtu.be/NexWmQN5gY8

I'm getting back into making videos after a long break, so I'd really like honest feedback.

Question for everyone: what's your debugging setup in React Native? Do you use DevTools breakpoints, Flipper, console.log, or something else? And is there a debugging topic you'd like me to cover next?

r/reactnative • • 12d ago

Tutorial What I learned going from React Native to Swift to build an Apple Watch app

35 Upvotes

I've done React Native for about 7 years. This year I needed an Apple Watch app (plus iPhone and Mac), and React Native doesn't run on watchOS, so I had to go native. A few things I wish I'd known before starting:

1) SwiftUI feels familiar faster than you'd think. Views are a function of state, u/State works a lot like useState and an u/Observable class is close to a small store. The mental model from React carries over almost one to one.

2) The watch is a different world. The screen is tiny and the system suspends your app very quickly, so you can't count on it staying open. Anything that has to reach the user right away is better sent as a notification than kept alive inside the app.

3) Live Activities and the Dynamic Island are their own thing. They're SwiftUI widgets with tight limits on how often they update, and to update them from a server you need push tokens. Plan that early, it's not like updating a normal screen.

4) Signing is the real boss fight. Mac, iPhone, watch and the widget extension each need their own bundle ID, capabilities and profiles. Most of my lost hours were there, not in the code.

5) Xcode Previews replace hot reload, partly. They're good for layout, but anything that depends on real data or the watch talking to the phone has to be tested on device.

6) I used Claude Code as a tutor. I'd ask it for the Swift version of a React Native pattern I already knew and to explain the differences. That got me productive in days instead of weeks.

Would I go native again? For watch apps, widgets and Live Activities, yes. For a regular app with forms and lists I'd still pick React Native.

Happy to answer questions if anyone is thinking about doing the same.

r/reactnative • • Jul 21 '26

Tutorial How I reduced iOS simulator RAM usage by up to 4×

125 Upvotes

I’ve made a small command line tool called simslim.

It disables background services inside iOS simulators that usually are not needed during development, like Siri, Spotlight indexing, photo analysis, News, and iCloud sync.

On my M1 Pro with 16 GB of RAM, one simulator went from around 4 GB of memory and 258 processes to about 0.9 GB and 70 processes. I managed to run 19 simulators at once, compared to around 5 before things started falling apart.

Some simulator features stop working depending on what gets disabled, so it is not meant for every kind of testing. You can keep specific services running when needed.

Give it a try: https://github.com/MobAI-App/simslim

r/reactnative • • 2d ago

Tutorial Spent way too long on an Android crash with nothing in Metro. logcat had the answer the whole time

13 Upvotes

Posting this because I lost a stupid amount of time on it and I doubt I'm the only one.

App just closes on Android. No red screen, nothing in Metro, DevTools disconnects. I did what everyone does: rerun, clear cache, paste the code into AI a few times.

The reason was in logcat the whole time. Native code threw, the app died before JS could say anything, and the Android log had the exact line.

What worked for me:

- open the android folder in Android Studio and open Logcat (it picks up the app even if you started it with yarn run android)

- clear it, then reproduce the crash

- set the level to Error and search FATAL EXCEPTION

- read the exception message first, then the first line in the stack trace that isn't Handler / Looper / ActivityThread. Click it and it jumps to the code

One thing that got me: in the terminal, filtering by pid after a crash gives you nothing because the process is gone. adb logcat -d -s AndroidRuntime worked better.

Also the stack trace only told me where it died, not who passed the bad value. I needed a breakpoint for that part.

I made a small demo crash and recorded the whole thing for anyone who'd rather watch than read: https://youtu.be/oVYBmnOVaI8

What do you check first when Metro says nothing?

r/reactnative • • Sep 22 '26

Tutorial I added a native ImageViewer to my Expo component library — An image that opens out of the page over a blur

20 Upvotes

Pressing a trigger moves its picture from where it sits in the page to the middle of the screen, shown whole, and blurs everything behind it. Once it is open, pinch or double-tap to zoom, swipe sideways to the other images under the same ImageViewer, and drag the picture up or down or tap outside it to send it back to its place.

Part of PanelUI, an open-source component library for Expo. Copy-paste or CLI, you own the source.

github.com/panel-ui/PanelUI

r/reactnative • • Feb 20 '21

Tutorial Book list app using reanimated 2, shared element transitions and lottie

609 Upvotes

r/reactnative • • 11d ago

Tutorial Debugging native iOS crashes in React Native 0.87.1 with Xcode 27.1 and LLDB

0 Upvotes

**Setup**

- React Native 0.87.1

- Xcode 27.1

- iOS Simulator (iPhone 18 Pro, iOS 27.0)

I've hit this a lot: the app dies on iOS, the JS console is quiet, and it's not obvious where to start. Most of the time the answer is on the native side, so here's the process I use. I call it RIFT.

**R – Reproduce**

Run the app from Xcode (not just from the terminal) and trigger the crash. Add a breakpoint near where you think it happens so you can pause instead of watching the app die.

**I – Investigate**

When it stops or crashes, look at the exception message and the backtrace in the left panel. In my example, a native module method called from JS threw an uncaught NSException, and the console printed the reason. Then in LLDB:

- `bt` – print the backtrace

- `frame select <n>` – jump to a specific frame

- `po` / `p` / `expression` – inspect values at that point

**F – Fix**

Change the actual cause in the native code (in my case, the method wasn't validating its input), not just the symptom.

**T – Test**

Re-run the exact same steps and confirm the crash is gone. Skipping this step is how "fixed" bugs come back.

I recorded a ~22 min live walkthrough of this on a real crash if it's useful to anyone:

https://youtu.be/oGq0yZ3z9ks

Happy to answer questions. What's your usual first step when a crash shows no JS error?

r/reactnative • • May 15 '26

Tutorial Update: shipped the app you helped me design. A few RN/Expo learnings

Post image
50 Upvotes

A few weeks back i posted here asking which design to go with for my weekly challenge app. THANK YOU so much for all the input! I iterated on the branding as per your feedback and released the app.

It's the first time i'm building a RN/Expo app so I wanted to share my findings, frustrations and some of the commands/choices i made.

quick brief: every week the app gives you a small dare. cold showers, talk to a stranger, phone-free mornings, etc. you commit for 7 days and take one polaroid as proof. Over time you build your "Scrapbook" with memories

Project Structure

I ended up going with a typescript monorepo. Simple stuff: bun/hono server, RN client and Tanstack Start webapp. I'm actually quite happy with the setup i did, used a common biome and tsconfig across the board. For sure something that

stack: expo, uniwind (tailwind for rn), zustand (app state) + react query (server state) + sqlite + kvvm (storage)

Was quite happy with this setup, will for sure use it again for my next project. If you want more info, I've documented the setup here.

Expo dev

I had to move away from Expo GO almost immediately as some the packages i use are not supported. Setting up a dev server is quite easy but the Camera doesn't work on simulators!!

Sadly, i bit the bullet and paid 99$ apple dev profile so i can test on my phone. This became the main testing device I used.

Expo builds

Once i had something to show, I pushed it to Test Flight so my fiance/friends can play with the product. I HIGHLY recommend doing this as you get a LOT of feedback early on. There are so many things i didn't see whilst developing, it's crazy man (skill issue too i'm sure).

Initially I used expo's cloud offering to build and submit the app to apple connect. That was a huge pain in my ass.. well over 90m for a build...

I've got a mac so i decided to build locally. It took me like 1-2 hours to setup, but I got a pretty good flow:

  1. First build the project (be sure to set EAS_LOCAL_BUILD_WORKINGDIR as it will fail otherwise)EAS_LOCAL_BUILD_WORKINGDIR=$HOME/eas-build-tmp bunx eas-cli@latest build --local --platform ios --profile production
  2. Submit using the Transporter app - worked perfectly

Takes around 10m e2e using a macbook pro with 16 gigs of ram. Not bad

Apple review was weirdly chill

3 days end to end, fast and friendly. two gotchas worth knowing:

  1. You have to test on ipad even if your app isn't for ipad. when an iphone-only app runs on ipad the screen (ironically) ends up tiny and that's where my layout broke and my review got declined.
  2. You NEED to put your terms of service link in your app store description? Strange cause there's already a field for this, but required. Cause of this my second review failed.

Reviewers also flagged a couple of genuinely nice optimisations for me. cheapest QA pass i've ever had, honestly.

Building solo with claude

Got way better with practice. Mostly about setting up the right context (CLAUDE.md files, splitting work into discrete tasks). still very much learning here - genuinely curious how others are doing it. Lmk if you want my setup.

All i can say is that the impeccable skill did some heavy lifting! - but you still need to rely on your brain. don't just ask it to take YOUR decisions.

r/reactnative • • Jun 22 '25

Tutorial Uber Clone App with React Native | Live Location Tracking with socket and background geolocation.

143 Upvotes

Video link: https://youtu.be/wO-yQq94FNA?si=Tp5hXBxPVmg0e-_s

In this, I have implement live driver location tracking using background location services and socket.io.

What we cover in this video:

  • How to fetch driver location in the background
  • Sending live coordinates to the server via socketio
  • Real-time location updates on the map
  • Backend connection and testing the socket flow
  • Android/iOS permission handling tips

r/reactnative • • Jul 27 '26

Tutorial I added 9 loading animations to PanelUI one prop to swap between all of them

22 Upvotes

<Loader variant="wave-physics" />

That's it. Nine variants, one prop. Swap between them without changing anything else same size, same color, same reduced motion behavior.

All animations run on the UI thread. Nothing re-renders while they run.

Part of PanelUI, an open-source component library for Expo. Copy-paste or CLI, you own the source.

GitHub link in the comments.

r/reactnative • • Aug 20 '26

Tutorial Why OTA Updates can take days to be installed

3 Upvotes

OTA tools love to say "instant updates", but it's not really true. Even though the release is instant, going from server to installed can take days if you use default settings.

It's not something I've seen discussed much, so I wanted to write a quick overview.

If you've used OTA Updates e.g. Expo Updates or a CodePush clone, you probably know the flow for each device goes:

  1. Checks for update
  2. Download the update
  3. Install the update

With each being triggered by defined conditions, which typically have slow defaults.

For example with Expo Updates, the default behaviour [doc] is for the check to happen on next cold start. If an update is available, it will download it, but then the install happens on the next cold restart after that.

For CodePush-based SDKs, it depends on when you call sync(), and whether you override the install mode (defaults to ON_NEXT_RESTART).

A cold restart means either the user swiped to close the app, or it was in the background long enough for the OS to close it. That means you can potentially get a situation like:

  1. Release an OTA update to the server
  2. User takes a few days before a cold reboot happens
  3. The update is downloaded, ready to install
  4. Another few days passes before another cold reboot
  5. The update is finally installed.

Having users hang around on the old version isn't ideal, but the good news is you can speed it up.

For a reasonable speed, we can have the app check for an update on resume, then install it when it's next in the background for more than a minute. For CodePush-based SDKs such as Patch, this is easy to wire up.

To check for updates on resume, we want to wire the sync() to be called using AppState, and we want installMode to use ON_NEXT_SUSPEND

import { useEffect } from "react";
import { AppState } from "react-native";
import { sync } from "@codemagic/react-native-patch";

const syncOptions = {
  installMode: "ON_NEXT_SUSPEND" as const,
  mandatoryInstallMode: "IMMEDIATE" as const,
  minimumBackgroundDuration: 60_000, // 1 minute
};

export default function App() {
  useEffect(() => {
    // Optional but usual: also check once at launch
    void sync(syncOptions);

    const sub = AppState.addEventListener("change", (next) => {
      if (next === "active") {
        void sync(syncOptions);
      }
    });

    return () => sub.remove();
  }, []);

  return <YourApp />;
}

The minimumBackgroundDuration is useful as the install will reboot the app to the its home screen, unless you persist navigation state and restore it on startup. Setting a minimum duration stops their view being lost if they only briefly switched apps.

For more urgent installs, CodePush based SDKs also have a mandatoryInstallMode, often set to IMMEDIATE. Like it sounds, this will install the update as soon as it's downloaded. The downside is that this also causes a reboot, which can feel like buggy behaviour if the user is already interacting with the open app.

Expo Update has its own methods such as Updates.fetchUpdateAsync() that you can use for customizing the install behaviour, although the docs note that background installs are experimental.

r/reactnative • • Aug 26 '26

Tutorial I Created a Package Called rn-story which lets you add Instagram-Style Stories to Your React Native App in Minutes

Post image
38 Upvotes

Images, videos, progress bars, and tap gestures — with rn-story, a lightweight, TypeScript-first stories component that works out of the box with Expo.

Stories are everywhere. Instagram, WhatsApp, Snapchat, LinkedIn, even food delivery apps — the full-screen, tap-to-advance format has become one of the most recognizable UI patterns in mobile.

Play around with the component here: https://snack.expo.dev/@abdullahansari/rn-story-demo

And it looks simple. A full-screen image, some progress bars, tap left, tap right. How hard can it be?

Harder than it looks. Building stories from scratch means solving a surprising number of small problems at once:

  • Progress bars that stay perfectly in sync with image durations and video lengths
  • Tap zones for next/previous that don’t conflict with long-press-to-pause
  • Resuming a paused story with the remaining time, not the full duration
  • Videos that report their own duration — eventually, asynchronously, sometimes never
  • Loading states that don’t trap the user when a network image stalls

I built rn-story to solve all of that in a single component, and version 2.0 is a ground-up rewrite with a full test suite behind it. This post shows you how to ship a complete stories experience — avatar rail, full-screen viewer, video support — in a few minutes.

What you get

  • 📸 Image and video stories with an animated progress bar per story
  • 👆 The gestures users expect: tap right for next, tap left for previous, long-press to pause, release to resume
  • 🔗 An optional “See More” link per story (the swipe-up pattern, as a button)
  • 🧩 A custom header slot — perfect for an avatar, username, and close button
  • 🔊 Video volume and mute controls
  • 📞 Navigation callbacks for building multi-profile flows
  • 🛡️ Written in TypeScript — every prop and the Story object are fully typed
  • 🪶 No native code of its own — works with Expo without ejecting

Installation

expo-av (which powers video stories) is a peer dependency, so install it alongside the package with the version that matches your Expo SDK:

npx expo install rn-story expo-av

Not using Expo? Install both with npm and make sure Expo modules are configured in your bare React Native project:

npm install rn-story expo-av

Your first story in ten lines

import Stories from 'rn-story';
import type { Story } from 'rn-story';

const stories: Story[] = [
  { media: 'https://example.com/photo.jpg', mediaType: 'image' },
  { media: 'https://example.com/clip.mp4', mediaType: 'video' },
];

export default function MyStories() {
  return <Stories stories={stories} />;
}

That’s a working viewer: full-screen media, animated progress bars, tap navigation, long-press to pause. Images show for 3 seconds by default (configurable per story with duration), and videos play for exactly as long as the video lasts — the progress bar syncs to the duration the video reports.

The gestures, for free

Everything users already know from Instagram works out of the box:

  • Tap the right half → next story
  • Tap the left half → previous story
  • Long-press anywhere → pause the story and its progress bar
  • Release → resume from where it left off — with the remaining time, not a restarted bar
  • Android back button → wired to an onClose callback you provide

A real stories rail

A lone viewer isn’t how stories ship. The real pattern is a horizontal rail of avatars; tapping one opens that profile’s stories; finishing them moves to the next profile; going back past the first story returns to the previous profile.

That flow is exactly what the navigation callbacks are for. onNext/onPrevious fire on ordinary navigation, and two dedicated callbacks fire at the edges: onAllStoriesEnd when there's nothing left to play forward, and onPreviousFirstStory when the user backs out of the first story.

import { useCallback, useState } from 'react';
import { SafeAreaView, ScrollView, Pressable, Image, Text } from 'react-native';
import Stories from 'rn-story';
import type { Story } from 'rn-story';

type Profile = {
  id: number;
  profileName: string;
  profileImage: string;
  stories: Story[];
};

const PROFILES: Profile[] = [
  {
    id: 1,
    profileName: 'Abdullah',
    profileImage: 'https://picsum.photos/id/64/200/200',
    stories: [
      {
        media: 'https://picsum.photos/id/1015/1080/1920',
        mediaType: 'image',
        seeMoreUrl: 'https://abdullahansari.me',
      },
      {
        media: 'https://picsum.photos/id/1016/1080/1920',
        mediaType: 'image',
        duration: 12000, // this one stays up for 12 seconds
      },
    ],
  },
  {
    id: 2,
    profileName: 'Pug life',
    profileImage: 'https://picsum.photos/id/1025/200/200',
    stories: [
      {
        media: 'https://download.samplelib.com/mp4/sample-5s.mp4',
        mediaType: 'video',
      },
      {
        media: 'https://picsum.photos/id/1025/1080/1920',
        mediaType: 'image',
      },
    ],
  },
];

export default function App() {
  // null means the story viewer is closed
  const [current, setCurrent] = useState<number | null>(null);

  const close = useCallback(() => setCurrent(null), []);

  // Finished a profile? Move on to the next one, or close after the last.
  const nextProfile = useCallback(() => {
    setCurrent((i) =>
      i === null ? null : i < PROFILES.length - 1 ? i + 1 : null
    );
  }, []);

  // Backed out of the first story? Go back a profile, or close on the first.
  const previousProfile = useCallback(() => {
    setCurrent((i) => (i === null || i === 0 ? null : i - 1));
  }, []);

  return (
    <SafeAreaView>
      <ScrollView horizontal>
        {PROFILES.map((profile, index) => (
          <Pressable
            key={profile.id}
            onPress={() => setCurrent(index)}
            style={{ alignItems: 'center', margin: 8 }}
          >
            <Image
              source={{ uri: profile.profileImage }}
              style={{
                width: 64,
                height: 64,
                borderRadius: 32,
                borderWidth: 2,
                borderColor: '#25D366',
              }}
            />
            <Text numberOfLines={1}>{profile.profileName}</Text>
          </Pressable>
        ))}
      </ScrollView>

      {current !== null && (
        <Stories
          stories={PROFILES[current].stories}
          onAllStoriesEnd={nextProfile}
          onPreviousFirstStory={previousProfile}
          onClose={close}
        />
      )}
    </SafeAreaView>
  );
}

Two details worth noticing:

Swapping stories just works. When onAllStoriesEnd moves current to the next profile, the component receives a new stories array and restarts cleanly from the first story. You don't need to unmount and remount anything, and you don't need to manage keys.

The viewer closes by unmounting. Rendering <Stories /> conditionally is the whole show/hide mechanism — no visible prop to keep in sync.

Make it yours

The header is a per-story ReactNode, so the avatar row you see in every stories UI is just your own component — typically an avatar, a username, and a close button, often over a subtle gradient:

const storiesWithHeader = profile.stories.map((story) => ({
  ...story,
  header: (
    <MyStoryHeader profile={profile} onClose={close} />
  ),
}));

Other knobs you’ll probably reach for:

<Stories
  stories={stories}
  isMuted={muted}              // mute video stories
  videoVolume={0.8}            // 0.0 – 1.0
  animationBarColor="#fff"     // progress bar fill
  animationBarHeight={2}
  isAnimationBarRounded        // rounded bar ends (default)
  seeMoreText="Read more"      // label for the See More button
  loadingComponent={<MySpinner />} // shown while media loads
  currentIndex={2}             // start (or jump) to a specific story
/>

And if a story has a seeMoreUrl, a pill-shaped button appears at the bottom and opens the link — the classic "swipe up" pattern without the swipe.

What’s new in 2.0

Version 2 is a full rewrite of the playback engine, and the first release with a real test suite (30 tests) behind it. The highlights:

  • stories and currentIndex are now reactive — swap in the next profile's stories without remounting
  • Video stories start and advance reliably, and a video that fails to load is skipped instead of freezing the viewer
  • Pause/resume now resumes with the remaining time, so the bar never drifts from reality
  • onNext/onPrevious no longer fire at the list edges — only the dedicated edge callbacks do
  • New onClose prop wires up the Android hardware back button
  • Story, StoriesProps, and StoryMediaType types are exported
  • expo-av moved to a peer dependency, so it always matches your Expo SDK

If you’re upgrading from 1.x, the README has a short migration table — it’s a five-minute change for most apps.

Wrapping up

Stories are one of those features that looks like an afternoon and turns into a week once progress bars, gestures, and video timing enter the picture. rn-story packs that week into an npm install.

If it saves you that week, a star on GitHub genuinely helps other people find it — and if you hit anything odd, open an issue. It’s MIT-licensed, and contributions are welcome.

r/reactnative • • Jun 26 '25

Tutorial Demo of a local-first sketch app I built with RN — works offline, syncs in real-time

262 Upvotes

✅ No loading spinners

✅ Works offline

✅ Real-time collaboration

✅ Multi-device sync

✅ Zero backend

✅ Private by default

✅ Built in 30 minutes

Built with Expo, Instant & Reanimated.

🎥 YouTube: https://youtu.be/DEJIcaGN3vY

⚡ Instant: https://instantdb.com

😮 Already a Pro? Here's the source code 👉 https://github.com/betomoedano/sketch-app

r/reactnative • • Jul 30 '26

Tutorial I built a Calendar component for Expo with no date library — single, range, and multiple selection

20 Upvotes

No date-fns, no dayjs, no moment. Month names and all the arithmetic come from Intl, so the component adds zero dependencies to your project.

Three modes: single day, date range, and multiple selection. For range, each cell draws its own piece of the band behind the number rather than as a background native has no pseudo-classes, so this is how you get clean ends where two cells meet without a gap or a seam.

Also supports: disabled days via a rule (disabled={(date) => isWeekend(date)}), minDate/maxDate for both selection and paging, and month/year dropdown for birthday pickers.

Part of PanelUI, an open-source component library for Expo. Copy-paste or CLI, you own the source.

r/reactnative • • Sep 19 '26

Tutorial React Native is DEAD, Expo Modules 2.0, and a $49 Flutter knockoff

Thumbnail
thereactnativerewind.com
0 Upvotes

Hey Community,

We dive into Expo Modules 2.0, which drops definition() in favor of Swift macro decorators to deliver build-time type conversion and faster native calls. Meanwhile, DartNative enters the scene, letting Flutter developers swap out Flutter's custom renderer for real platform views driven by Yoga.

We also look into Shopify rebuilding its apps in native Swift and Kotlin with AI agent workflows, examining what their departure means for community maintained libraries like FlashList and Skia.

r/reactnative • • 24d ago

Tutorial How the old react native bridge worked

20 Upvotes

i used react native for years without knowing how it worked inside.

so i learned it and wrote it up with simple animations.

https://chamidilshan.medium.com/how-react-natives-old-bridge-architecture-worked-and-why-it-was-replaced-612e7313bce1

r/reactnative • • 25d ago

Tutorial I built a way to collect in-app feedback in React Native without building a backend

0 Upvotes

Every app I shipped needed the same boring things: a feedback form, somewhere to store reports, screenshot uploads, and a way to reply to users. I kept rebuilding them.

So I built PanelUI Studio. You install an SDK, add a publishable key, and reports land in an inbox your team can reply from. The user sees the reply inside the app and can answer.

A report is one call:

- message, rating, tags, and the screen it came from

- screenshots uploaded straight from the device

- platform, OS, and app version filled in automatically

- anonymous by default, so apps without accounts still work

It works with any Expo or React Native app. It also pairs with the Feedback dialog from PanelUI, my open-source component library, but you don't need the library to use it. There's a free plan.

Curious how you all handle feedback today: reviews, support email, or something in-app?

https://studio.panelui.dev/

r/reactnative • • 28d ago

Tutorial How deferred deep linking actually matches an install in React Native (after Firebase Dynamic Links)

4 Upvotes

Since Firebase Dynamic Links shut down in August 2025, a lot of RN apps lost the "tap a link, install, land on the right screen" flow. I've been building a replacement for the past year, so here is how the matching works under the hood and where it quietly breaks. Useful whether you roll your own or use any provider.

**The core problem:** an install from the App Store or Play Store carries nothing from the link the user tapped. On first launch your app has to reconnect "this fresh install" to "that click" some other way. There are three ways to do it.

**1. Play Install Referrer (Android only).** If the Play Store URL carries a referrer parameter, Google Play hands it to your app on first launch. It is exact, needs no permissions, and is the best option on Android. It only works for installs that came through a Play Store URL with that parameter.

**2. Clipboard (mostly iOS).** The landing page copies the link before sending the user to the App Store, and the app reads it on first launch. It is exact, but since iOS 16, reading the pasteboard shows the "Allow Paste" prompt. If that fires the moment your app opens, many users tap Don't Allow and it feels sketchy. Use it as a fallback, not the first thing you try.

**3. Fingerprint.** At click time the server stores signals like IP, device model, OS version and language, then compares them on first open. No permissions, but it is probabilistic. Shared wifi, carrier NAT, VPNs and long gaps between click and open all hurt accuracy. Keep the match window short, and consume a match once so two people on the same network don't get each other's link.

**Things that silently break it:**

* Returning the same match on every launch, so users get sent to an old promo forever. Route once, then clear it.

* Universal Links or App Links failing verification. Common causes: the AASA or assetlinks.json file is served behind a redirect, with the wrong content type, or with your upload key's SHA256 instead of the Play App Signing key. The link then opens the browser instead of your app, and nothing errors.

* Links opened inside the Instagram, TikTok or Facebook browsers, which often don't hand Universal Links to your app. Users land on your web fallback even with the app installed.

* Testing by reinstalling over an existing build. Test the real path: uninstall, tap the link, install from the store, open once.

Happy to answer questions about any of it, including building it yourself.

Disclosure: I build Flinku (flinku.dev), which does this for RN with a free tier.

r/reactnative • • Jul 09 '25

Tutorial Bottom Sheet in One Command Line

149 Upvotes

BNA UI: Bottom Sheet
Add a Bottom Sheet to Your Expo App React Native with Just One CLI Command with BNA UI! 🚀
npx bna-ui add bottom-sheet

r/reactnative • • Sep 20 '26

Tutorial Release - Ask Buoy an AI chat inside your running app, like the Claude Chrome extension but for mobile!

0 Upvotes

Ask Buoy is a chat inside your running app. Think the Claude Chrome extension and Claude Code in one, aimed at a live mobile app(Dev,Stg,Prod): it sees the screen, presses what's there, and reaches into state, network and navigation underneath that no one else can see.

If a Buoy tool can do it, you can ask for it in a sentence, so debugging, testing and support stop being separate skill sets. A customer says an offer looks wrong? Ask Buoy to impersonate their account, open the screen, and compare what the API returned with what's rendered. It finds the mismatch while you're still on the call. Force an error state, override an API response, change live data, send a push, jump to a screen.

r/reactnative • • Sep 18 '26

Tutorial I added a native BumpChart to my Expo component library for rankings that change over time

8 Upvotes

A line chart shows how a value moved. A bump chart shows how a ranking moved and that's a different question.

The rows are evenly spaced regardless of the scores behind them. That's the point: order matters here, not distance. If distance matters, use a line chart of the scores instead.

More than three or four lines get hard to follow through the crossings. Pass highlight to pick one out it draws in its colour on top, and the rest go muted underneath.

Pass the raw scores instead of ranks and the chart figures out the order itself per column. Switch the data and every line moves to its new places.

Part of PanelUI, an open-source component library for Expo. Copy-paste or CLI, you own the source.

https://github.com/panel-ui/PanelUI

r/reactnative • • Sep 23 '26

Tutorial Uninstalling Cursor, Extreme PR Makeovers, and 33 Percent Less Thread-Blocking JSON

Thumbnail
thereactnativerewind.com
1 Upvotes

Hey Community!

Jay Meistrich built Legend Code, a lightweight code editor designed strictly for viewing single files without heavy agentic UI overhead. On the workflow front, Aleksander Mikucki introduced Screenmap, a GitHub Action that uses iOS simulator screenshots and visual diffs to show reviewers exactly which screens your PR modifies.

We also cover the Expo SDK 58 Beta with foldable device support, React Native 0.88 with DOM-aligned event listener APIs, Reanimated 4.7 defaulting to its new layout engine, and Nitro LazyJSON cutting JavaScript thread blocking by 33%. Plus, cloud testing tools like EAS Simulator and Software Mansion's SimCam.

r/reactnative • • Dec 28 '25

Tutorial First Ever React Native Security Scanner is Live: Zero config, One command

Post image
87 Upvotes

Hey RN community,

Today, I released rnsec, an open-source security scanner built specifically for React Native apps.

In the age of AI and vibe coding, hope this can be a lifesaver.

Links: https://www.rnsec.dev https://www.npmjs.com/package/rnsec https://github.com/adnxy/rnsec

The goal is simple: catch common mobile security issues before they reach production.

What it checks: - Hardcoded API keys & secrets - Insecure usage - Cleartext HTTP traffic (Android/iOS) - Weak auth patterns - Risky WebView configs - Platform misconfigurations - 60+ other security rules

Why rnsec: - HTML & JSON reports - Zero configuration - One command to run - Fast and lightweight - 100% local – code never leaves your machine CI/CD ready

How to use: Install: npm install -g rnsec Run: rnsec scan

This is first version, so looking for feedback, stars and support ❤️

Next version will include 100+ security rules!

I have years of work into security and hope this will improve our community and RN as a safe place for development