A personal practice studio for senior React Native interviews. Rehearse spoken pitches with the
teleprompter, drill technical Q&A as flashcards, and master every requirement a senior mobile role asks for —
all in English.
10Practice pitches
40+Q&A flashcards
10Architecture topics
C1Target English level
Step 1
Warm up your story
Open Pitches, pick the 30s and 60s intros, and run the teleprompter while you record. Aim for calm, clear delivery — not memorized perfection.
Step 2
Build the foundation
Read the Architecture and Study Guide tabs. Every topic is tied back to something you've actually shipped, so it's recall, not cramming.
Step 3
Drill & track
Test yourself with Q&A flashcards and tick off the Progress checklist until every box is green.
The senior RN role in one glance
What these roles hire for
A senior contributor who owns and evolves the front-end systems behind a mobile product —
typically in a fast-moving, experiment-driven environment (A/B tests, feature flags, analytics) on a
mature React Native codebase, collaborating closely with product, design, and backend.
Native mobile (Swift / Kotlin), CI/CD, store releases
Testing — unit & integration — and refactoring legacy code
Logistics to confirm
Hours & commitment (e.g. full-time, 8 hrs/day)
Remote setup and any time-zone overlap — be ready to say a clear yes
Which team / surface you'd own (discovery, search, growth…) — then map it to your experience
Your edge
You've built discovery & directory surfaces, real-time chat, and performance fixes on a mature app already. Lean into that.
Practice Pitches
Ten spoken answers covering the full interview range — short and long intros, “why React Native”,
“why this company”, a technical deep-dive, and three behavioral STAR stories. Tap ▶ Teleprompter on any pitch to
rehearse on camera with a scrolling script, timer, and speed control.
How to practice
Don't memorize word-for-word — it sounds robotic. Learn the shape of each answer (the beats), then say it
in your own words. Record, watch once, fix one thing, record again. Three takes beats thirty re-reads.
Pitch 01
The 30-second intro
“Tell me about yourself” — short~30 sec
Hi, I'm Gerardo — a senior mobile engineer with more than ten years in JavaScript and the last six focused on React Native. I've shipped eight-plus apps to the App Store and Google Play.
Most recently I led the mobile work on Valt Connect, a private-markets app, where I owned real-time chat, biometric auth, performance, and the store releases — in TypeScript, with Expo, React Query, and Zustand.
I'm drawn to this role because it's senior, fully remote, and React Native at its core.
Delivery & English tips
Keep it light and confident — this is a handshake, not your life story. Land on the three nouns:
chat, auth, performance. Pronounce biometric as “bye-oh-MET-rik”, auth as “awth”,
and Zustand as “ZOO-stand”. Smile on the last line — it signals genuine interest.
Pitch 02
The 60-second intro
“Tell me about yourself” — standard~60–75 sec
Sure. I'm Gerardo Cordero, a senior mobile engineer working fully remote from Latin America. I have over ten years of full-stack JavaScript, and since 2019 I've specialized in cross-platform mobile with React Native.
In that time I've shipped more than eight apps across about ten companies and five industries — private markets, financial education, telecom, home services, and consumer apps.
For the last two years I was the lead engineer on a two-person mobile team building Valt Connect, a private-markets app for investors. I built real-time chat with Twilio Conversations, biometric login with FaceID and TouchID, and Salesforce-based authentication — and I owned our production releases and App Store review responses. A big part of that work was performance: I removed re-render flickering and frozen screens, and added optimistic updates across the app.
My daily stack is React Native, Expo, TypeScript, React Query, and Zustand, and I'm comfortable in large, evolving codebases and monorepos. I'm looking for a senior, remote React Native role where I can go deep on a mature product — which is exactly what this is.
Delivery & English tips
Structure = who I am → what I've shipped → my best story → my stack → what I want. Pause briefly
between paragraphs; those pauses read as confidence. Watch Twilio (“twi-LEE-oh”),
authentication (“aw-then-ti-KAY-shun”) and optimistic (“op-ti-MIS-tik”). Don't rush the
last sentence — it's your “I want this job” line.
Pitch 03
The 2-minute career story
“Walk me through your background”~2 min
I'll give you the short arc. I started as a full-stack JavaScript developer about ten years ago — Meteor, Angular, then React — working remotely for startups and agencies. I learned to own things end to end early: frontend, backend, deployments, even Linux servers.
Around 2019 I found my focus: mobile. I moved into React Native and never looked back. At Novacomp I shipped five apps to the stores for US clients — discovery apps like SplashSpot and Hotspotters — and at the same time I learned AWS Amplify on the job: Cognito, AppSync GraphQL, Lambda, DynamoDB. That period taught me how to ramp fast on an unfamiliar stack and still deliver.
The last three years were my deepest chapter. Through TrueNorth and then directly at Valt Network, I was the lead mobile engineer on Valt Connect, a private-markets app. I architected a schema-driven form builder reused across a Turborepo monorepo, integrated Twilio real-time chat and PSPDFKit for native PDF rendering, and migrated us to native deep linking. As the senior voice on a two-person team, I owned releases, code reviews, and performance.
What ties it all together is range — I've been the backend person, the PM, the interviewer, and the performance specialist — but mobile is the craft I love most. That's why a senior, React-Native-first role on a mature, experiment-driven product is exactly the next step I want.
Delivery & English tips
Tell it as a journey with one turning point (“around 2019 I found my focus”). That single line makes
the whole story feel intentional. Hard words: Turborepo (“TUR-bo-REE-po”), monorepo
(“MON-o-REE-po”), schema (“SKEE-ma”), PSPDFKit (just say “P-S-P-D-F-Kit”). End on the word
“next step” — it frames you as moving toward them, not away from a job.
Pitch 04
Why React Native — and why mobile
Motivation / technical conviction~60 sec
I came to React Native from full-stack JavaScript, so at first it was just practical — one language, two platforms. But what made me stay is that mobile is where engineering constraints are real. You're designing for the worst phone, the worst network, and a battery the user actually watches.
React Native sits in a sweet spot for that: I get the velocity of JavaScript and a shared codebase, but I can still drop into Swift or Kotlin and write a native module when I need to — like I did patching PSPDFKit and building custom camera-permission hooks.
And the platform has genuinely matured. The New Architecture — Fabric, TurboModules, JSI — is the default now, Hermes ships by default, and the old bridge bottleneck is gone. So the old “React Native is slow” argument really doesn't hold anymore if you know how to profile and optimize, which is exactly the part I enjoy.
Delivery & English tips
This answer shows conviction + current knowledge. Saying “the old bridge bottleneck is gone” signals
you're up to date. Pronounce Fabric (“FAB-rik”), JSI (“J-S-I”), Hermes (“HUR-meez”),
Kotlin (“KOT-lin”). Avoid sounding like a fanboy — note the trade-off honestly: RN is great
when you know how to profile.
Pitch 05
Why this company
Company motivation · reusable framework~60 sec
Reusable structure — fill the [brackets] for each company before you record.
Three things pull me to [company]. First, the product and its values — [the mission or value that genuinely resonates with you]. Building software where [the impact it has on users] is the kind of work I want to put my name on.
Second, the engineering reality fits me exactly. You're a mature React Native product with a sophisticated codebase, and I do my best work in large, evolving systems — I've spent the last three years deep in one. Joining the [team you'd join] is almost on the nose: [the surface — e.g. search, filtering, discovery] is precisely what I built on Valt Connect and on my consumer discovery apps.
Third, the way you work — [experiment-driven / craft-focused / whatever they emphasize]. I like building where data tells us if we were right, not opinions. So it's the right product, the right codebase, and the right way of working, all at once.
Delivery & English tips
Keep it professional and warm. Research the company first and fill every [bracket] with something
specific and true — vague flattery is obvious. The “rule of three” (product, codebase, way of working) keeps you
organized. Connecting their team to your résumé (“almost on the nose”) is the strongest move — always do it.
Pitch 06
Signature project — Valt Connect (technical deep-dive)
“Walk me through a project you're proud of”~2 min
The project I'm proudest of is Valt Connect — a private-markets mobile app for investors and deal teams. I joined for the first cross-platform release and stayed as the lead engineer on a two-person mobile team for about three years.
On the architecture side, the most reusable thing I built was a schema-driven form builder — a package that renders forms, validation, and error handling from a schema, shared across apps in a Turborepo monorepo. That turned weeks of form work into hours.
For real-time, I integrated Twilio Conversations as a singleton provider — chat rooms, unread tracking, private flows, and push notifications. For trust and security I built Google Sign-In, biometric auth with FaceID and TouchID, an App-Store-compliant account deletion flow, and Salesforce auth through External Connected Apps for secure token management.
I also integrated PSPDFKit for native PDF rendering of investor statements, with a custom toolbar and a couple of native module patches, and I moved us from Firebase deep links to native universal links on both platforms.
The part I care about most is performance and ownership: I tracked down re-render flickering and frozen screens, added optimistic updates across profiles and bookmarks, and I owned the production releases and the App Store review responses end to end.
Delivery & English tips
Use the structure context → architecture → features → performance/ownership so the interviewer can
follow you. Don't list everything flatly — pause before “the part I care about most” to spotlight the
performance work, since that's what the JD cares about. If they want depth, the form builder, the Twilio
singleton, and the re-render fix are your three deep-dive doors.
Pitch 07
STAR — the hardest performance bug
Behavioral · problem-solving~90 sec
Situation. On Valt Connect, users were hitting flickering lists and screens that froze for a second or two when navigating between profiles and feeds. On a premium app for investors, that felt cheap, and it was hurting trust.
Task. As the senior mobile engineer, I owned getting us back to smooth, 60-FPS interactions without a big rewrite.
Action. I profiled instead of guessing. I measured re-renders and found components re-rendering on every state change because of unstable props and context values. I memoized the expensive components, stabilized callbacks and selectors, and moved frequently-changing state out of broad contexts into Zustand so only the components that actually used a slice re-rendered. For the frozen screens, I moved heavy work off the critical render path and added optimistic updates so actions like bookmarking felt instant instead of waiting on the network.
Result. The flickering was gone, navigation felt immediate, and the bookmark and profile flows updated instantly. Just as important, I turned it into a habit on the team — profile first, then fix the specific re-render, rather than sprinkling memo everywhere and hoping.
Delivery & English tips
Say the four words — Situation, Task, Action, Result — quietly as signposts; interviewers love a
clean STAR. The killer line is “I profiled instead of guessing” — it shows senior judgment. Watch
memoize (“MEM-oh-ize”) and selector (“se-LEK-tor”). End on the lesson, not just the fix —
that's what separates senior from mid.
Pitch 08
STAR — ownership & leading without a title
Behavioral · leadership / initiative~90 sec
Situation. At Valt we were a two-person mobile team owning a growing app, with product, design, and backend all moving fast around us. There was no one above me on mobile to defer to.
Task. I had to be the person who set the bar — technically and operationally — while still shipping features every sprint.
Action. I took ownership of the things that are easy to neglect on a small team. I built the shared form-builder package so we'd stop rewriting forms. I set up our release process and owned App Store submissions and review responses, including a compliant account-deletion flow. I did the code reviews, kept the codebase testable, and added version-based cache invalidation so we could push fixes without breaking older clients. When something was ambiguous, I asked product the clarifying questions early instead of guessing.
Result. We shipped consistently and cleanly for years with a tiny team, and the form builder and release process outlived any single feature. Earlier in my career I'd also run recruiting interviews and mentored a junior developer, so stepping into that senior, set-the-standard role felt natural.
Delivery & English tips
This answers “are you senior?” without bragging — you show ownership through specifics (releases,
reviews, cache invalidation). “Leading without a title” is a strong, humble frame. Don't speed up here;
ownership stories land better calm and measured. Watch ambiguous (“am-BIG-yoo-us”) and
invalidation (“in-val-i-DAY-shun”).
Pitch 09
STAR — thriving in a fast, changing environment
Behavioral · adaptability / learning~90 sec
Situation. At Novacomp I was hired as a frontend mobile developer, but the client work needed full backends on AWS — and I'd never touched Amplify or AppSync.
Task. I had to deliver production backends for our React Native apps without slowing the team down, while priorities shifted between several client apps.
Action. I treated it like any unfamiliar codebase: learn the smallest piece that unblocks the next feature, ship it, repeat. I picked up Cognito and OAuth, AppSync GraphQL, Lambda, DynamoDB, and OpenSearch on the job, leaning on docs and small spikes. In parallel I kept shipping the mobile side and even took on some PM coordination with the clients. I'd done this before — at Bits Kingdom I drove the team through React Native 0.59 to 0.62 upgrades and the Hermes rollout — so I trusted the process of ramping fast under pressure.
Result. We shipped five apps to the stores in that period, with me owning both the frontend and the backend I'd just learned. That experience is exactly why a fast, experiment-driven environment appeals to me — shifting priorities and new tools are where I'm comfortable.
Delivery & English tips
This maps straight to the JD's “adaptability” and “fast-moving, experiment-driven” language — echo those
words. Your repeatable method (“learn the smallest piece that unblocks the next feature”) is the gold; say it
clearly. Pronounce Amplify (“AM-pli-fy”), Cognito (“cog-NEE-toe”), OpenSearch. Close by
tying it back to them.
Pitch 10
The closing — “why should we hire you?” + your questions
Closing statement~60 sec + questions
If you're asking why me — it's fit on three levels. The role is senior React Native on a mature, experiment-driven product, and that's the exact environment where I've spent the last three years and done my best work. The team's surfaces — [search, filtering, the area you'd own] — are things I've shipped before. And I bring the senior habits you actually need day to day: I profile before I optimize, I write tested and reusable code, and I own work through QA and store release, not just to “done on my machine.”
On logistics, I'm fully set up for remote, I can commit to the time-zone overlap you need, and I'm comfortable being the kind of engineer who asks the clarifying question early and communicates clearly with non-technical teammates.
And a couple of questions I'd love to ask you: What does the team's experimentation loop look like today — how quickly can an engineer get an A/B test in front of users? And where is the codebase on the New Architecture migration — fully on Fabric, or still in progress?
Delivery & English tips
Closing strong matters — recruiters remember the last 60 seconds. Reuse the “three levels of fit” frame for
consistency, then proactively confirm remote + time-zone overlap (if they asked, answer before they do).
Ending with two sharp questions flips you from candidate to colleague. Keep the questions specific —
“experimentation loop” and “New Architecture migration” both prove you understand the role.
Mobile Architecture Guide
A senior-level tour of mobile system design, mapped onto React Native and the New Architecture.
This is the “how do you think about building a mobile app at scale” material.
System design is decision-making before code. On mobile specifically, interviewers want to see that you
design for the worst phone, the worst network, and the worst moment — not lab conditions. This
five-step framework keeps you structured under pressure:
Step
What you do
Time
C — Clarify
Functional vs non-functional requirements, scale (DAU/MAU), platforms, online/offline expectations. Spend 4–6 min here — most candidates rush it and design the wrong system.
~15%
R — Rough HLD
Draw the high-level diagram: the four layers and the major components. A “city map, not a street map.”
~20%
D — Deep dive
Zoom into one component (repository, chat service, image loader) — interfaces, methods, patterns, edge cases.
~35%
D — Discuss trade-offs
Name the alternatives and why you chose one. This is the senior signal.
~20%
S — Summarize
Recap the design, call out risks, handle follow-ups.
~10%
Senior tell A line like
“I'd use the Repository pattern plus stale-while-revalidate plus single-flight refresh” shows you can name
patterns and combine them. Always say the trade-off out loud — “I'm trading freshness for speed here.”
Your proof You already do the C-step instinctively — your CV
literally lists “proactively ask clarifying questions.” Lead with that in any design round.
02 · The 4-layer architecture & patterns
Almost every mobile app shares the same skeleton. Memorize it — it's your HLD template:
Pattern evolution: MVC → MVP → MVVM (view binds to a view-model exposing observable state) → MVI
(one-way data flow, immutable state, reducers) → Clean Architecture (strict layer boundaries, dependencies
point inward). In React Native, the idiomatic shape is essentially MVVM/MVI: components observe a store,
dispatch actions, and a unidirectional data flow updates the UI.
Your proof Your schema-driven Form Builder is layered thinking in
action — a reusable domain package decoupled from any one screen, shared across a Turborepo monorepo.
03 · The networking layer
A production API client has six separated pieces: (1) the HTTP engine, (2) the serializer, (3) a typed API
service interface, (4) interceptors for cross-cutting concerns (auth token, logging, retries), (5) DTOs that
match the server JSON, and (6) the repository that wraps it all and adds caching. Never let DTOs leak into the
UI — map them to domain models first.
Errors, retries, timeouts
Wrap calls in a result type (success / failure), set sane timeouts, and retry only idempotent requests with
exponential backoff + jitter. Distinguish retryable (network, 5xx) from non-retryable (4xx) failures.
Pagination
Strategy
How
Use when
Offset / limit
?page=3&limit=20
Small, stable lists; jump-to-page
Cursor
Opaque token to the next slice
Feeds & infinite scroll — stable under inserts (the usual right answer)
Keyset
WHERE id < lastId
Large datasets, performance-critical
Your proof Discovery/global-directory surfaces with search + filters
on Valt, and the AppSync GraphQL + OpenSearch data layer at Novacomp, are exactly this layer at work.
04 · Storage & caching
Two layers, different speeds and lifetimes: memory cache (RAM — fastest, lost on kill) and disk cache
(SQLite / Realm / MMKV / files — survives restarts). Caching buys you speed, battery, data savings, and offline
support; the cost is complexity — you must decide what to cache, where, when to evict, and when it's stale.
Eviction vs invalidation
Eviction = removing data to free space: LRU (drop least-recently-used) and TTL (expire after N seconds).
Invalidation = knowing cached data is stale. Strategies: time-based (TTL), event-based (push/mutation invalidates a key), and version-based (bump a version to bust old clients).
The pattern to nameStale-while-revalidate: show cached data instantly,
fetch fresh in the background, reconcile. It's the heart of React Query and SWR — render cache, refetch, update.
Your proof You shipped version-based cache invalidation on Valt
so fixes could ship without breaking older clients, and you've used React Query and SWR for years.
05 · Offline-first design
Offline-first flips the model: the local database is the source of truth, and the network just keeps it in sync.
The UI always reads from local storage, so the app keeps working with no signal. Three building blocks:
Optimistic updates — apply the change locally and update the UI immediately, then confirm with the server and roll back on failure. Makes likes, bookmarks, and sends feel instant.
Sync queue + replay — queue mutations made offline, then replay them in order when connectivity returns.
Conflict resolution — when local and server disagree: last-write-wins (simple), server-wins, or merge/CRDT (richest). Pick per data type.
Your proof You added optimistic updates across profiles and bookmarks on
Valt — the exact pattern an interviewer wants you to describe here.
06 · Real-time updates
Technique
How it works
Best for
Polling
Client asks every N seconds
Simple, low-frequency data; wastes battery if abused
Long polling
Server holds the request until data is ready
Near-real-time without WebSocket infra
WebSocket
Full-duplex persistent connection
Chat, presence, live trading — true two-way real-time
SSE
One-way server → client stream
Feeds, notifications, live scores (server push only)
Push (FCM/APNs)
OS-level delivery when app is backgrounded/killed
Re-engagement, messages while app is closed
Decision guide: two-way + low latency → WebSocket. One-way stream → SSE. App closed → push notification.
Don't keep a socket open just for occasional updates — it drains battery (remember the radio “tail energy”).
Your proof Twilio Conversations on Valt is a WebSocket-backed real-time
system — you built the singleton provider, unread tracking, and push notifications on top of it.
07 · Performance essentials
App launch — minimize work before first paint; lazy-load, defer non-critical init. TurboModules help by initializing native modules on demand.
Smooth 60 FPS scrolling — virtualize long lists (FlatList/FlashList), keep renderItem cheap, stabilize keys, avoid anonymous inline functions/objects in props.
Re-render discipline — React.memo, useMemo/useCallback, store selectors so a component re-renders only on the slice it uses. Profile first; don't sprinkle memo blindly.
Battery & network — batch network calls (the radio's “tail energy” makes 10 small calls far worse than 1), cancel work when the user leaves a screen, schedule background sync.
Your proof This is your signature: you eliminated re-render flickering and
frozen screens on Valt by profiling, memoizing, and moving hot state into Zustand selectors.
08 · Security basics
HTTPS + certificate pinning — encrypt in transit; pin to defeat man-in-the-middle on hostile networks.
Token storage — never in AsyncStorage. Use the iOS Keychain and Android Keystore (e.g. react-native-keychain / expo-secure-store).
Encryption at rest — encrypt sensitive local data (SQLCipher, encrypted MMKV).
Auth flows — OAuth 2.0 / OIDC with PKCE, short-lived access tokens + refresh tokens, biometric gating for sensitive actions.
Your proof Biometric auth (FaceID/TouchID), Google Sign-In, Salesforce
External Connected Apps for secure token management, Cognito + OAuth (Google/Apple/Facebook) — you've shipped the
whole auth stack.
09 · React Native — the New Architecture
This is the highest-leverage topic for a senior RN interview in 2026. Know the before/after cold:
Old (legacy bridge)
New Architecture
Async Bridge serializing JSON between JS & native — a batching bottleneck
JSI (JavaScript Interface): JS holds C++ references and calls native synchronously, no JSON bridge
Paper renderer (async UI)
Fabric: new concurrent renderer with a shared C++ shadow tree; enables synchronous layout & better React 18 concurrent features
Codegen: type-safe native interfaces generated from TS specs
Status to quote: the New Architecture has been the default since React Native 0.76 (late 2024); Hermes
is the default JS engine; and the legacy bridge is being fully removed (disabled by default around 0.82). Expo apps get
it out of the box on recent SDKs. Hermes matters because it precompiles to bytecode for faster startup, lower
memory, and smaller bundles.
Say this “JSI replaced the bridge, Fabric replaced the renderer, TurboModules
replaced native modules, and Codegen makes it all type-safe — it's the default since 0.76, so the old ‘RN is slow because
of the bridge’ critique is basically historical now.”
10 · The RN threading model & mobile constraints
Classic React Native runs on three threads: the JS thread (your React code & business logic), the
native/UI (main) thread (rendering, gestures), and a shadow thread (Yoga layout). Jank happens when you
block the JS thread (heavy synchronous work) or thrash the bridge. The New Architecture + JSI reduce cross-thread cost,
and tools like Reanimated run animations on the UI thread so they stay smooth even if JS is busy.
The four constraints that shape every decision: limited resources (battery, memory, CPU, storage),
unreliable networks (2G→5G→offline), the app lifecycle (foreground / background / killed), and the fact
that you ship to millions of different devices you don't control. Design for the worst case and the happy path
takes care of itself.
Your proof You've debugged the render thread, driven a Hermes rollout,
and shipped on a wide device range — speak to the threading model from having actually fought jank, not theory.
Every requirement a senior React Native role commonly asks for, explained at senior depth and tied to
where you've already done it. Read the concept, then read the “your proof” line so you can speak from experience,
not theory.
Be honest, then bridge Three areas are likely lighter on your CV than
the JD wants: MobX, deep GraphQL caching, and heavy native code. Each card below flags a “close the
gap” note so you can answer truthfully and show you can ramp — exactly the senior move.
What they want: strong commercial RN/JS/TS — not tutorials, production apps. TypeScript fluency: typed
props and hooks, discriminated unions for state, generics for reusable utilities, strict null-safety, typing API
responses so the compiler catches shape mismatches.
Your proof 10 yrs JS, 8 yrs React/RN, 5 yrs TypeScript, 8+ shipped apps. TS is
your daily driver on Valt. Talk about how typing DTOs and store slices prevents whole classes of runtime bugs.
02 · New Architecture, lifecycle, rendering & performance
What they want: deep understanding of the New Architecture (Fabric, TurboModules, JSI, Codegen, Hermes),
component lifecycle (mount → render → commit → effects), why re-renders happen, and how to optimize. See the
Architecture · New Architecture section for the full breakdown.
Concurrent React (18/19) — transitions, useDeferredValue — and how Fabric enables it.
Lists: FlatList windowing, getItemLayout, FlashList for heavy feeds.
Your proof You profiled and killed re-render flicker and frozen screens on Valt,
and drove a Hermes rollout at Bits Kingdom. You can speak to rendering from the trenches.
03 · State management — Zustand & MobX
What they want: senior RN JDs increasingly name Zustand and MobX specifically. You're strong on Zustand;
MobX is the one to brush up.
Zustand (your strength)
A tiny store created with create(); components subscribe with a selector so they re-render only when
their slice changes. No providers, no boilerplate, works outside React. Talk about selector discipline and
shallow equality to avoid extra renders.
MobX (close the gap)
MobX is transparent reactive state: you mark state observable, wrap components in
observer(), and they automatically re-render when the exact observables they read change. You mutate state
directly inside actions, and computed values derive cached state. Mental model: a spreadsheet —
change a cell, every formula that depends on it recalculates.
Zustand
MobX
Style
Immutable-ish, selector subscriptions
Mutable, observable + reactions
Re-render trigger
Selector result changes
Observed field changes
Updates
set(state => …)
mutate inside an action
Derived state
compute in selector
computed (cached)
How to say it honestly “My production depth is in Zustand and Redux, and
I've used Context and React Query for server state. I've worked with MobX's model — observables, observer components,
actions, and computed values — and since I understand reactive state deeply, I'd be productive in your MobX code quickly.”
Then pivot to a Zustand performance story you own.
Key distinction to landServer state vs client state. React Query/SWR
own server cache (fetching, caching, revalidation); Zustand/MobX own client/UI state. Mixing them up is a common
mistake — keep them separate.
04 · GraphQL & efficient data-fetching
What they want: integrate with GraphQL services and understand efficient fetching + caching. Senior talking
points: query only the fields you need (vs REST over-fetching), a normalized cache (Apollo/urql store entities by
id so one update reflects everywhere), pagination with cursors + fetchMore, optimistic responses, and
cache invalidation after mutations.
Your proof You built and consumed AppSync GraphQL at Novacomp (Cognito,
Lambda resolvers, DynamoDB, OpenSearch) and you've used React Query/SWR caching with optimistic updates for years —
the same caching instincts transfer directly to Apollo/urql.
Close the gap Skim Apollo Client's normalized cache & cache.modify,
and be ready to contrast a normalized cache (Apollo) with a query-key cache (React Query). One sentence on
each shows real understanding.
05 · Native iOS / Android development
What they want: hands-on native (Swift, Objective-C, Kotlin, Java), native SDK integration, and build-config
changes when RN isn't enough. You don't need to be a full native engineer — you need to be the RN engineer who isn't
afraid of the native side.
Writing/patching a native module or TurboModule; bridging a native SDK to JS.
Your proof PSPDFKit native integration with native module patches, custom
iOS/Android camera-permission hooks, native universal/deep-link handling, and owning app IDs, certificates, and
notification setup on Apple Developer + Google Cloud.
How to say it honestly “I'm comfortable dropping into native to integrate
an SDK, patch a module, or fix build config — I've done PSPDFKit patches and native permission hooks. I'm not writing
large Swift/Kotlin features daily, but I read it, debug it, and ship the native glue RN needs.”
06 · Complex, large-scale & legacy codebases
What they want: ramp fast on a big, evolving codebase and contribute without breaking things. Method: read the
data flow before the files, find the smallest safe change, lean on types and tests, follow existing patterns rather than
importing your own.
Your proof Three years inside one growing app (Valt), Turborepo monorepo tooling,
and a documented habit of “quickly understand and contribute to a large, evolving codebase.” You've also built
shared packages others depend on.
07 · Testing & quality
What they want: low post-release bug rate via real testing — unit, integration, and CI-gated E2E. Know the
pyramid: many fast unit tests (Jest), fewer integration tests (React Native Testing Library — test behavior, not
implementation), few E2E (Maestro / Detox) on critical flows. Talk about testable architecture: pure functions, injected
dependencies, thin components.
Your proof Jest unit & integration, CI-gated E2E, and Maestro on your CV;
you set up CI test pipelines from scratch (Bitbucket Pipelines) early in your career. “Maintain a testable and reusable
codebase” is literally a line you live.
08 · CI/CD, releases & third-party SDKs
What they want: own the path to production — CI/CD pipelines, App Store + Google Play releases, third-party SDK
integration. Know: build automation (EAS Build / Fastlane / GH Actions), OTA updates (EAS Update / CodePush) and their
limits (JS-only, not native), staged rollouts, and release/review processes.
Your proof You owned production releases and App Store review responses on
Valt, used Expo EAS for CD, GitHub Actions, App Center, and integrated SDKs like Twilio, PSPDFKit, OneSignal, Stripe, and
In-App Purchases. This is a clear strength — lead with it.
09 · Refactoring, tech debt & stability
What they want: reduce crash rates and tech debt with direction. Approach: measure first (Sentry/Crashlytics for
crash-free rate), refactor behind tests in small safe steps, strangle legacy patterns gradually rather than big-bang
rewrites, and tie every refactor to a metric (startup time, crash rate, re-renders).
Your proof Performance refactors on Valt (re-render & frozen-screen fixes),
version-based cache invalidation for safe rollouts, and driving RN 0.59→0.62 + Hermes upgrades — all stability work.
10 · Experiment-driven development
What they want: this is core to experiment-driven product teams — A/B tests, feature flags, analytics-driven iteration. Know:
feature-flag patterns (gradual rollout, kill switches, flag hygiene/cleanup), how an experiment is instrumented (assign
variant → fire events → read metrics), guardrail metrics, and writing code that can run two variants cleanly.
Your proof You've worked analytics + tracking (Google Analytics, App Center,
OneSignal) and shipped iteratively with product as a PM-adjacent engineer. Frame your delivery style as “ship, measure,
iterate.”
Close the gap Be ready to name tools by category — flags (LaunchDarkly,
Statsig, or a homegrown system), analytics (Amplitude/Mixpanel/Segment) — and say you adapt to whatever they use.
11 · Debugging, profiling & troubleshooting
What they want: strong, systematic debugging. Toolbelt: React DevTools Profiler & the “why did this render”
tooling, Flipper / the new RN DevTools, Hermes profiler, native instruments (Xcode Instruments, Android Profiler),
Sentry breadcrumbs, and network inspection. Method: reproduce → isolate → measure → fix → add a regression test.
Your proof Flipper profiling, render-thread debugging, and the Valt performance
investigation are your headline debugging stories. “I profile instead of guessing” is your signature line.
12 · Soft skills & collaboration
What they want: adaptability, attention to detail (pixel-perfect, clean code), initiative, team play, and clear
communication with non-technical stakeholders. In a remote, PST-overlapping role, written clarity and proactive
updates matter as much as code.
Your proof You acted as PM with clients, ran recruiting interviews, mentored a
junior dev, and coordinated dev/design teams. You explain technical things to non-technical people for a living — say so.
Go deeper The cards above map the job description. The set below pushes into
core mechanics and newer concepts a senior RN engineer is expected to reach for — each still tied to where you've
touched it, with a “new concept” note where it's genuinely fresh ground to learn.
13 · Navigation & deep linking
Core: navigation is a tree of navigators — stack (push/pop), tabs, and drawer — that you nest
to model real apps. Screens receive typed params; useFocusEffect and useIsFocused run
work only while a screen is active. Deep links map an incoming URL (myapp://chat/42 or an https
universal link) to a screen + params via a linking config, so a push notification or email lands the user on the exact
screen.
Auth-gated flows: conditionally render the auth stack vs the app stack — never just hide screens.
Persisting navigation state across restarts; resetting stacks cleanly after login/logout.
New conceptExpo Router — file-based routing (a file in
app/is a route), nested _layout files, typed routes, and <Link prefetch>.
It's becoming the default; learn how its file tree compiles down to the same React Navigation tree underneath.
Your proof You shipped universal/deep-link handling on Valt and owned app
IDs, associated domains, and notification setup — so URL→screen routing and the native link config are things you've
actually wired, not just read about.
Core: the old Animated API drives values from the JS thread, so motion stutters whenever JS is
busy. Reanimated fixes this by running animation code in worklets on the UI thread — useSharedValue
holds the value, useAnimatedStyle maps it to styles, and withTiming/withSpring animate
it at 60fps even while the JS thread is blocked. Gesture Handler processes pan/tap/pinch natively and composes
gestures (simultaneous, race, sequence).
Worklets: tiny functions marked to run on the UI thread; hop back with runOnJS, into it with runOnUI.
Layout Animations — declarative entering/exiting/layout props for enter/exit.
useDerivedValue for values computed from other shared values without re-rendering React.
New concept The UI-thread mental model: an animation that never
touches React's render is the secret to smoothness. Internalize what runs where — worklet (UI) vs JS — and you can
explain jank precisely instead of hand-waving.
Your proof You eliminated re-render flicker and frozen screens on Valt —
the same instinct (keep work off the thread that's busy) is exactly why Reanimated's UI-thread model wins. Say it as
“I already think in terms of which thread is doing the work.”
15 · Accessibility (a11y)
Core: make the UI work with VoiceOver (iOS) and TalkBack (Android). Mark elements
accessible, give them an accessibilityRole (“button”, “header”, “image”), a clear
accessibilityLabel, and accessibilityState (selected / disabled / checked). Respect Dynamic
Type (text scales with the OS font setting), keep touch targets ≥ 44pt, and meet WCAG AA contrast.
AccessibilityInfo — detect a running screen reader; announceForAccessibility for live updates.
Manage focus after navigation; group related elements; hide purely decorative ones from the reader.
Honor reduce-motion for users who disable animations.
New concept Accessibility is a senior signal, not a nice-to-have —
it's tested (accessibility inspector, automated a11y lint) and often a compliance requirement. Being the engineer who bakes
it in early reads as craftsmanship.
Your proof Your pixel-perfect, detail-oriented reputation is the bridge:
position a11y as that same care extended to users on assistive tech. Even one shipped VoiceOver pass is a strong story.
16 · Mobile security deep-dive
Core: the JS bundle ships to the device and can be read — never put secrets in it. Store tokens in the
iOS Keychain / Android Keystore (via expo-secure-store or react-native-keychain), not
AsyncStorage (plaintext). Handle access/refresh tokens carefully, gate sensitive actions behind biometrics, and use
HTTPS everywhere (ATS on iOS). Know certificate pinning (trust only your cert/CA) and its rotation tradeoff.
OWASP MASVS / Mobile Top 10 — the vocabulary interviewers expect: insecure storage, weak crypto, and so on.
Jailbreak/root detection and code obfuscation as defense-in-depth (not silver bullets).
Attestation: App Attest (iOS) / Play Integrity (Android) to verify a genuine app and device.
New concept “Parse the threat model out loud”: secrets-in-bundle, data at
rest, data in transit, and device integrity are four distinct buckets. Naming them shows senior security maturity.
Your proof You shipped FaceID/TouchID biometric auth, Google Sign-In, and
Salesforce auth on Valt — real auth and sensitive-data flows. You've already made the secure-storage and token
decisions; now you can name the framework (Keychain/Keystore, MASVS) around them.
17 · Memory management & leak hunting
Core: two memory worlds — the JS heap (managed by Hermes' GC) and native memory (views, images,
native modules). The classic RN leaks: event listeners, subscriptions, and timers you never clean up; stale closures that
capture large objects; and screens retained by navigation. The fix is disciplined useEffect cleanup,
AbortController to cancel in-flight fetches, and removing listeners on unmount.
Images are the biggest native memory cost — downsample, cache sensibly, avoid huge bitmaps in lists.
Inline objects/functions in render feed churn and can keep references alive longer than expected.
New concept Leaks show up as slow, cumulative jank and crashes after
long sessions — not an immediate bug. You hunt them with a profiler over time, not a single stack trace.
Your proof Your frozen-screen and re-render investigation on Valt is
lifecycle/memory discipline, and the Hermes rollout you drove improved GC behavior directly. “I profile memory across
a session instead of guessing” extends your signature debugging line.
18 · App startup, bundling & Metro
Core:TTI (time-to-interactive) is the metric. At launch the OS inits the native app, then the JS bundle
loads and the first screen renders. Metro is RN's bundler; Hermes precompiles JS to bytecode at build
time so there's no parse step on-device — faster cold start, lower memory. Cut startup further with inline requires /
lazy loading so modules load on first use, not all at boot.
Shrink the bundle: tree-shaking, React.lazy + Suspense for heavy screens, trim/curate dependencies.
Optimize assets (image sizes, font subsetting); measure cold vs warm start separately.
Splash → first paint: don't block the first frame on network or heavy synchronous work.
New concept Treat startup as a budget: every eagerly-imported module
and synchronous boot task spends milliseconds. Senior teams track TTI like a metric and defend it in code review.
Your proof You drove a Hermes rollout (Bits Kingdom) and led RN 0.59→0.62
upgrades — startup, bytecode, and bundle work is literally on your CV. You can speak to before/after launch time from
real rollouts.
19 · Advanced TypeScript & runtime validation
Core: past the basics, seniors lean on discriminated unions to model state machines (impossible states won't
compile), generics for reusable hooks/utilities, utility types (Partial, Pick,
Omit, Record), as const for literal inference, and branded types so a
UserId can't be passed where an OrgId is expected.
Template-literal & mapped/conditional types for typed routes, event names, and API shapes.
Type navigation params and API DTOs end-to-end so the compiler catches shape drift.
New conceptTypes are compile-time only — they vanish at runtime, so a
bad API response still crashes you. Validate untrusted JSON at the boundary with zod (or io-ts): write the schema
once, infer the type from it, and “parse, don't validate.” One schema = a single source of truth for type + check.
Your proof 5 yrs TypeScript, typing DTOs and store slices on Valt — you
already prevent whole classes of shape bugs at compile time. Runtime validation (zod at the network edge) is the next layer,
and an easy, current thing to add to your vocabulary.
20 · Observability & production health
Core: once it ships you run on signals. Sentry / Crashlytics capture crashes; crash-free users %
is the headline metric. Upload source maps (Hermes needs its bytecode source maps) so traces symbolicate to real
files/lines. Breadcrumbs reconstruct the steps before a crash, and performance monitoring surfaces slow renders, slow
screens, and ANRs.
Release health: watch a new version's crash rate and halt or roll back on a spike.
OTA updates (EAS Update / CodePush) — track adoption, keep a rollback path, and remember OTA is JS-only.
Tie dashboards/alerts to guardrail metrics so regressions page you, not your users.
New conceptRelease-health gating: a deploy isn't “done” at submit —
it's done when the crash-free rate holds across the rollout. Treating monitoring as part of shipping is a senior tell.
Your proof You owned production releases and App Store review responses on
Valt and used App Center, analytics (GA), and OneSignal — plus EAS for CD. Your “ship, measure, iterate” style with
crash-free rate as the guardrail is exactly this card.
Tap a card to reveal the answer, then grade yourself. Your grades are saved in this browser, so you
can come back and drill only the ones you still need.
Known 0 / 0
RNWhat is React Native's New Architecture and what problem does it solve?
It replaces the legacy async Bridge with four pieces: JSI (direct JS↔C++ calls, no JSON serialization), Fabric (a new concurrent renderer), TurboModules (lazy native modules), and Codegen (type-safe native interfaces from TS specs). The problem it solves is the bridge bottleneck — everything used to be serialized to JSON and batched asynchronously, which caused jank and slow startup. It's the default since RN 0.76.
RNWhat is JSI and why does it matter?
JSI (JavaScript Interface) is a lightweight C++ layer that lets JavaScript hold references to native objects and call their methods synchronously, without serializing to JSON over the bridge. It matters because it removes the single biggest performance bottleneck and enables Fabric and TurboModules. It also makes the engine swappable — that's how Hermes plugs in.
RNHow is Fabric different from the old (Paper) renderer?
Fabric is the new renderer built on JSI with a shared C++ shadow tree. It supports synchronous layout, concurrent React features (Suspense, transitions), and better interop with native views. The old Paper renderer was async-only and couldn't take advantage of React 18+ concurrency.
RNTurboModules vs the old NativeModules?
NativeModules were all initialized eagerly at startup, even unused ones. TurboModules are lazy — loaded on first access via JSI — which cuts startup time and memory. They're also type-safe through Codegen.
RNWhat is Hermes and why use it?
Hermes is the JS engine built for React Native. It precompiles JS to bytecode at build time, so there's no parse step at launch — giving faster startup, lower memory use, and smaller app size. It's the default engine in the New Architecture, with improved garbage collection.
RNHow many threads does React Native use and what runs where?
Classically three: the JS thread (your React code and logic), the native/UI (main) thread (rendering, gestures, native views), and a shadow thread for Yoga layout. Jank usually means you blocked the JS thread. Libraries like Reanimated run animations on the UI thread so they stay smooth even when JS is busy.
RNWhat does “bridgeless” mode mean?
Bridgeless removes the legacy bridge entirely — all JS↔native communication goes through JSI/Fabric/TurboModules. It became the default with the New Architecture, and the old bridge is being fully removed (disabled by default around RN 0.82). Result: faster startup and lower latency on native calls.
RNExpo vs bare React Native — when would you pick which?
Expo gives you managed builds, EAS Build/Update, config plugins, and a huge module library — great velocity, and modern Expo fully supports native code and the New Architecture. You go bare (or eject) only when you need something Expo's tooling truly can't express. For most teams today, Expo + dev clients is the productive default.
RNSince which version is the New Architecture the default?
Default since React Native 0.76 (late 2024), with Hermes as the default engine. Subsequent releases keep hardening it, and the legacy bridge is being removed (disabled by default around 0.82). Quoting this signals you're current.
RNHow would you integrate a native SDK that has no RN wrapper?
Write a thin TurboModule (or native module) that exposes just the methods you need: define a TS spec, implement it in Swift/Kotlin, bridge events via the emitter, and handle build config (Pods/Gradle, permissions). Keep the JS surface small and typed. I've done this kind of native glue — e.g. patching PSPDFKit and writing camera-permission hooks.
ARCHWalk me through how you'd approach a mobile system design question.
I use CRDDS: Clarify requirements (functional/non-functional, scale, platforms, offline) for several minutes first; sketch a Rough HLD with the four layers; Deep-dive one key component; Discuss trade-offs explicitly; then Summarize and handle follow-ups. The discipline is: clarify before designing, and always say the trade-off out loud.
ARCHWhat are the core layers of a mobile app architecture?
UI/Presentation (screens, components — render state, emit events), Business/Domain (use-cases, validation — framework-agnostic and most testable), Data/Repository (combines remote + local, caching, DTO→model mapping), and Network (HTTP client, serialization, interceptors). The UI talks to repositories, never directly to the API.
ARCHWhat is the repository pattern and why use it?
A repository is the single entry point for a domain's data. It hides whether data comes from network, cache, or DB, handles the stale-while-revalidate logic, and maps DTOs to clean domain models. Benefits: the UI stays decoupled from data sources, it's easy to test with a fake repo, and caching/offline logic lives in one place.
ARCHWhat does “offline-first” mean and how do you build it?
The local database is the source of truth; the network just syncs it. The UI always reads local data, so the app works with no signal. Building blocks: optimistic updates for instant feedback, a sync queue that replays offline mutations when connectivity returns, and a conflict-resolution strategy (last-write-wins, server-wins, or merge) per data type.
ARCHHow do optimistic updates work, and how do you roll back?
You apply the change to local state and update the UI immediately, before the server confirms — so an action like a like or bookmark feels instant. You keep the previous value; if the request fails, you roll back to it and surface an error. React Query's onMutate/onError/onSettled is the canonical implementation. I shipped exactly this across profiles and bookmarks on Valt.
ARCHCache eviction vs cache invalidation?
Eviction removes data to free space — LRU (drop least-recently-used) or TTL (expire after N seconds). Invalidation is knowing data is stale and refetching — time-based, event-based (a mutation or push invalidates a key), or version-based (bump a version to bust old clients). Eviction is about memory; invalidation is about correctness.
ARCHExplain stale-while-revalidate.
Show cached (possibly stale) data immediately so the screen is instant, then fetch fresh data in the background and reconcile the UI when it arrives. It's the core of React Query and SWR and the reason well-built apps feel fast — the user almost never stares at a spinner.
ARCHWebSocket vs SSE vs polling vs push — when do you use each?
WebSocket for two-way, low-latency (chat, presence, trading). SSE for one-way server→client streams (feeds, live scores). Polling/long-polling for simple or low-frequency updates without socket infra. Push (FCM/APNs) when the app is backgrounded or killed. Don't hold a socket open for occasional updates — it drains battery via radio tail energy.
ARCHOffset vs cursor vs keyset pagination?
Offset/limit is simple and supports jump-to-page but breaks under inserts and is slow on big tables. Cursor uses an opaque token to the next slice — stable for infinite feeds (usually the right answer). Keyset (WHERE id < lastId) is fastest for very large datasets. For a social feed, cursor.
ARCHWhat makes a robust API client?
Six separated pieces: HTTP engine, serializer, a typed service interface, interceptors (auth token, logging, retries), DTOs matching server JSON, and a repository that adds caching. Plus sane timeouts, a result type for errors, and retry-with-backoff only on idempotent calls. DTOs never leak into the UI.
ARCHMVVM vs MVI — and where does React Native land?
MVVM exposes observable state from a view-model that the view binds to. MVI adds strict one-way data flow with immutable state and reducers (intent → state → render). React Native is essentially MVVM/MVI: components observe a store, dispatch actions, and unidirectional flow re-renders the UI. MVI's predictability shines in complex, experiment-heavy screens.
STATEHow does Zustand work, and what's “selector discipline”?
You create a store with create() holding state + actions. Components subscribe with a selector — useStore(s => s.user) — and re-render only when that slice changes. Selector discipline means selecting the narrowest slice and using shallow equality for objects, so you don't re-render on unrelated updates. No providers, and you can read/write the store outside React too.
STATEExplain MobX's core model.
MobX is transparent reactive state: mark state observable, wrap components in observer(), and they auto-re-render when the exact observables they read change. You mutate state directly inside actions, and computed values are cached derivations. Mental model: a spreadsheet — change a cell, dependent formulas recalculate automatically.
STATEZustand vs MobX vs Redux — trade-offs?
Redux: explicit, predictable, lots of boilerplate, great devtools/time-travel. Zustand: minimal, selector-based, low ceremony, easy to scale. MobX: least boilerplate, mutable + automatic reactivity, very ergonomic but the magic can hide where re-renders come from. For a large experiment-driven app, Zustand and MobX both reduce boilerplate; the choice is team preference around explicit vs reactive.
STATEWhy separate “server state” from “client state”?
Server state is async, shared, and can go stale — it needs caching, deduping, background refetch, and invalidation, which is what React Query/SWR provide. Client/UI state is synchronous and local — toggles, form state, selected tab — which is what Zustand/MobX handle. Putting server data in a global UI store (or vice versa) is a classic mistake that leads to manual cache bugs.
STATEGraphQL normalized cache vs React Query's query-key cache?
Apollo/urql keep a normalized cache — entities stored by __typename:id, so updating one entity reflects everywhere it's referenced. React Query caches by query key — each query's result is a blob; you invalidate keys after mutations. Normalized is powerful for highly relational data; query-key is simpler and transport-agnostic. Knowing the distinction shows real data-layer depth.
STATEHow do you stop a global store from causing extra re-renders?
Subscribe to the narrowest slice via selectors, use shallow equality for object/array selections, split large stores into focused ones, and keep derived data in computed selectors/computed rather than recomputing in render. In MobX, read only the observables a component truly needs inside observer. Then verify with the profiler instead of assuming.
PERFA long list is janky while scrolling. How do you fix it?
Virtualize it (FlatList/FlashList) so only visible rows render; give stable keyExtractor; make renderItem cheap and memoized; avoid inline functions/objects in props; provide getItemLayout when row height is known; downsize images. Then profile to confirm the re-render count actually dropped. FlashList helps a lot for heavy feeds.
PERFHow do you reduce app startup time?
Minimize work before first paint: lazy-load heavy screens/modules, defer non-critical init off the launch path, lean on TurboModules (lazy native init) and Hermes (bytecode, no parse). Audit the bundle, trim unused dependencies, and measure TTI with the profiler. Splash-to-interactive is the metric to watch.
PERFWhen do useMemo/useCallback actually help — and when not?
They help when (a) a child is wrapped in React.memo and you must keep props referentially stable, or (b) a computation is genuinely expensive. They don't help — and add overhead — when wrapping cheap values or passing to non-memoized children. The rule: profile, find the real re-render or hot computation, then memoize that specific thing. Don't sprinkle them everywhere.
PERFWhich FlatList props matter most for performance?
keyExtractor (stable keys), getItemLayout (skip measurement), windowSize / maxToRenderPerBatch / initialNumToRender (tune the render window), removeClippedSubviews, and a memoized renderItem. For very heavy lists, switch to FlashList. Always pair changes with profiling.
PERFHow do you track down a memory leak or image-memory issue?
Watch memory in Xcode Instruments / Android Profiler while exercising the suspect flow. Common RN causes: listeners/subscriptions/timers not cleaned up in useEffect teardown, retained closures, and oversized decoded images. Fix by cleaning up effects, releasing off-screen resources, right-sizing and caching images, and re-measuring to confirm the curve flattens.
PERFHow does battery efficiency affect your network design?
The radio is the biggest battery drain and stays warm after each call (“tail energy”), so 10 small requests cost far more than 1 batched one. I batch and coalesce calls, cancel in-flight requests when the user leaves a screen, cache aggressively to avoid refetching, and schedule background sync for good conditions (charging/Wi-Fi) instead of constant polling.
TESTWhat's your testing strategy for a React Native app?
The pyramid: many fast unit tests (Jest) on pure logic, hooks, and reducers; a solid layer of integration tests with React Native Testing Library that assert behavior (what the user sees) not implementation; and a few E2E tests (Maestro or Detox) on critical flows like auth and checkout, gated in CI. I design for testability — pure functions, injected dependencies, thin components.
TESTUnit vs integration vs E2E — and the tools?
Unit: one function/hook in isolation (Jest). Integration: a component or screen with its store and mocked network, asserting user-visible behavior (React Native Testing Library). E2E: the real app driven like a user across screens (Maestro — simple YAML flows — or Detox). Balance: lots of unit, fewer integration, a handful of E2E on must-not-break paths.
TESTWhat does CI/CD look like for a mobile app, and what are OTA limits?
CI runs lint, types, unit/integration tests and a build on every PR; CD builds signed artifacts (EAS Build / Fastlane) and ships to TestFlight/Play internal tracks, then staged production rollout. OTA (EAS Update / CodePush) can push JS-only changes instantly — but anything touching native code or new native modules still requires a store build. Knowing that boundary is key.
TESTHow do you keep crash rate low after release?
Track crash-free rate with Sentry/Crashlytics, set error boundaries around risky screens, validate inputs and handle network failures gracefully, gate risky features behind flags with a kill switch, and roll out in stages so you catch regressions on 1–5% before 100%. Every crash gets a root-cause fix plus a regression test.
STARTell me about the hardest performance problem you solved.
See Pitch 07 for the full STAR. Headline: re-render flickering and frozen screens on Valt Connect; I profiled instead of guessing, found components re-rendering on unstable props/context, memoized them, moved hot state into Zustand selectors, and added optimistic updates. Result: smooth navigation, instant interactions, and a team habit of profiling first.
English tip: say the four STAR words quietly as signposts; end on the lesson, not just the fix.
STARTell me about a disagreement with product or design.
Frame it calmly: I disagree with data and options, not ego. Example shape — product wanted a feature that risked performance/scope; I laid out the trade-off (cost, risk, a lighter alternative), asked clarifying questions about the actual user goal, and we picked a phased path. The point I make: I push back early and in writing, then commit fully once we decide.
English tip: use “I'd frame the trade-off as…” and avoid words like “fight” — say “align” and “trade-off.”
STARHow do you ramp up on a large, unfamiliar codebase?
I read the data flow before the files — entry points, navigation, the store, the API layer — then make the smallest safe change to learn the feedback loop, leaning on types and tests. I follow existing patterns rather than importing my own, and I ask targeted questions early. I've done this repeatedly — learning AWS Amplify on the job at Novacomp and ramping into Valt's growing codebase.
English tip: “the smallest safe change that unblocks the next feature” is a clean, memorable phrase — use it.
STARDescribe a time you owned a release end-to-end.
On Valt I owned production releases and App Store review responses on a two-person team: cutting builds with EAS, managing signing and store metadata, shipping a compliant account-deletion flow, adding version-based cache invalidation so fixes wouldn't break older clients, and responding to App Store review feedback to get approvals through. Ownership through QA to production is something I actually did, not just helped with.
English tip: emphasize “I owned…” — it's the seniority word the JD repeats.
STARAre you comfortable with 100% remote and a large time-zone overlap (e.g. 6 hrs with PST)?
Yes — clearly and without hesitation. I've worked fully remote for most of my career across US and LATAM teams, I'm set up for it, and I can commit to a wide time-zone overlap. I work well async too: clear written updates, proactive flags on blockers, and asking the clarifying question early so time-zone gaps never stall the work.
English tip: answer the logistics question with a confident, short “Yes” first — then add detail. Don't hedge.
OPTThe single most important rule before optimizing performance?
Profile first. Measure to find the real bottleneck, fix that specific thing, then re-measure — never optimize on a guess.
OPTName three classic React Native memory-leak sources.
Listeners never removed, timers/intervals never cleared, and closures retaining large objects — all from a missing useEffect cleanup.
OPTWhy is index-as-key dangerous in a list?
On reorder/insert/delete, a recycling list reuses the wrong view for the data → visual glitches. Use a stable unique id instead.
OPTHow do you keep an animation smooth when the JS thread is busy?
Run it on the UI thread — Reanimated worklets or useNativeDriver:true — so it isn't blocked by JS work.
OPTTwo levers to cut JS bundle size?
Specific (deep) imports + tree-shaking (sideEffects:false), and minify/shrink with R8/Proguard. Visualize the bundle to find bloat.
OPTWhat does Hermes do for startup?
Precompiles JS to bytecode at build time → no runtime parse, faster TTI, lower memory. Default under the New Architecture.
OPTFlashList v2 prerequisite and benefit?
Requires the New Architecture; it auto-measures item layout synchronously, so no estimatedItemSize and smoother recycling.
AIThree benefits of on-device inference?
Privacy (data stays on the device), offline operation, and no server cost — plus low latency with small models.
AIMandatory setup before any model call?
initExecutorch() with a resource-fetcher adapter at the app entry; the library also requires the New Architecture.
AIWhy can't you use Expo Go for on-device AI?
It ships native code, so you need a development build (expo-dev-client + prebuild or EAS) — Expo Go can't load it.
AICrash-safety rule for an LLM screen?
Call interrupt() and wait for isGenerating===false before unmounting; only one LLM instance can be active at a time.
Smaller and faster with minimal quality loss (e.g. SpinQuant ≈ 42% smaller). Essential to fit mid-range devices.
AIBundle the model or download it?
Download large models from a remote URL with a progress UI and user opt-in; bundling is capped (<512MB) and bloats the binary.
Deep Dives — Optimization & On-Device AI
The senior playbook from two advanced guides, in a concept → example → problem → solution shape so each idea sticks as a real engineering decision, not a definition.
⚡ Performance Optimization
Startup
Cold start & Time-to-Interactive (TTI)
Concept TTI is the time from tap/launch to a screen the user can actually use. It's the headline cold-start metric and is dominated by JS bundle parse + everything you run before first paint.
Example A cold-start trace shows 2.5s: ~1.2s evaluating the JS bundle, ~0.8s in eager module/init work for screens the user hasn't even reached yet.
Problem Top-level imports of heavy libraries run their initialization at startup even when the first screen never uses them.
Solution Ship Hermes (bytecode, no parse), lazy/dynamically import non-critical screens, and defer non-urgent work with InteractionManager.runAfterInteractions(). Measure TTI before and after — don't guess.
Engine
Hermes — the JS engine
Concept Hermes precompiles JavaScript to bytecode at build time, so there's no parse/compile step on launch — lower startup time, lower memory, smaller footprint.
Example Switching a JSC app to Hermes drops Android TTI and steady-state memory measurably; check it's on with !!global.HermesInternal.
Problem On a non-Hermes engine the full JS source is parsed on every cold start, taxing low-end devices most.
Solution Hermes is the default under the New Architecture (0.76+). Profile CPU hotspots with the Hermes sampling profiler rather than reading code and guessing.
Rendering
Re-render discipline
Concept React re-renders on state / prop / context change. React.memo only helps if the props are referentially stable.
Example A parent passes a fresh inline object every render, so a memoized child re-renders anyway:
Problem A context holding a frequently-changing value re-renders every consumer, even ones reading an unrelated field.
Solution Stabilize props with useMemo/useCallback, split broad contexts, and move hot state into a store with selectors so only the slice's consumers re-render.
Lists
Long lists at scale
Concept Virtualization renders only visible rows; a recycling list (FlashList) reuses row views instead of mounting/unmounting them.
Example A 10k-row chat janks on a plain list but scrolls at 60fps on a recycling list with a cheap, memoized renderItem and a stable key.
Problem Using the array index as the key. On reorder/insert/delete, views get recycled onto the wrong data → visual glitches.
Solution Always use a stable unique id in keyExtractor, memoize renderItem, and provide getItemLayout for fixed-height rows. FlashList v2 auto-measures under the New Architecture (no estimatedItemSize).
Memory
Memory leaks
Concept A leak is a reference that outlives its usefulness, blocking GC. On a phone, repeated navigation churn turns a small leak into a crash.
Example Three classics — a listener, a timer, and a closure capturing a big object:
Problem Subscriptions never removed, intervals never cleared, or a long-lived callback that retains a large data structure.
Solution Always return a cleanup from useEffect; clear every timer; cancel every subscription; avoid capturing large objects in callbacks that live a long time. Confirm with the memory profiler that the curve flattens.
Bundle
Bundle size & tree-shaking
Concept A smaller JS bundle means faster download, parse, and TTI. Dead code that survives bundling costs you on every launch.
Example Importing a whole utility library vs. one function:
// ❌ pulls the whole library
import _ from 'lodash';
// ✅ only what you use (tree-shakeable)
import groupBy from 'lodash/groupBy';
Problem Barrel files and side-effectful modules defeat tree-shaking, so unused code ships anyway.
Solution Import specific paths, mark packages "sideEffects": false where true, visualize the bundle to find bloat, and enable minify + shrink (R8) on Android to strip dead native/JS code.
Threads
Animations & the JS thread
Concept Classic RN runs your code on the JS thread and rendering on the UI thread. If JS is busy, anything driven by JS stutters.
Example A gesture-driven animation stays at 60fps because it runs on the UI thread (Reanimated worklets / useNativeDriver: true) while a list does JS work.
ProblemAnimated without the native driver, or heavy layout/compute on the JS thread, drops frames during interaction.
Solution Run animations on the UI thread, set useNativeDriver: true, and push heavy compute off the critical path (defer with InteractionManager or a worklet).
Architecture
The New Architecture (Fabric · TurboModules · JSI)
ConceptJSI lets JS call native synchronously (no JSON bridge); Fabric is a concurrent renderer with a C++ shadow tree; TurboModules load native modules lazily.
Example Fabric's synchronous layout is exactly what lets a modern recycling list measure items on the fly instead of needing size estimates.
Problem The legacy bridge serialized and batched every call, adding latency on rapid native interactions and blocking concurrent React.
Solution Adopt the New Architecture (default since 0.76) and prefer libraries that support it; it's the foundation the other wins build on.
Method
Profiling-first methodology
Concept Optimization without measurement is guessing. Find the proven bottleneck, fix that, re-measure.
Example The React DevTools Profiler shows which component re-rendered and why; the Hermes sampler shows CPU hotspots; native profilers show memory growth.
Problem Sprinkling memo/useMemo everywhere adds overhead and complexity while often fixing nothing real.
Solution Reproduce → measure (render counts / flamegraph) → fix the hotspot → re-measure → lock it with a check so it can't regress.
🧠 On-Device AI
Concept
On-device inference — what & why
Concept The model weights live on the phone and all computation runs locally — no server round-trip. A small C++ runtime runs a model exported to a .pte binary, delegating to a hardware backend (CPU/XNNPACK by default).
Example A chat assistant runs a 1B quantized LLM fully offline via a declarative hook (useLLM), streaming tokens into the UI.
Problem Cloud inference means network latency, recurring GPU bills, and shipping users' audio/images/chats off-device.
Solution On-device inference buys privacy (data never leaves the device), offline use, no server cost, and low latency — at the price of RAM/storage budgeting.
Setup
New Architecture + mandatory init
Concept The runtime ships native code, so it requires the New Architecture (Fabric + TurboModules) and a one-time initialization with a resource-fetcher adapter before any model API is called.
Example
// app entry, once, before any model hook
import { initExecutorch } from 'react-native-executorch';
import { ExpoResourceFetcher } from 'react-native-executorch-expo-resource-fetcher';
initExecutorch({ resourceFetcher: ExpoResourceFetcher });
Problem Calling a model hook before init throws an "adapter not initialized" error; the old architecture is unsupported.
Solution Initialize at the app root. RN 0.76+ / modern Expo SDKs enable the New Architecture by default, so confirm it's on.
Tooling
Expo: you must use a dev build
Concept A library with native code can't run in the prebuilt Expo Go sandbox — it needs a custom development build.
Example Add expo-dev-client, then npx expo prebuild + npx expo run:ios -d (real device for iOS release), or build a dev client on EAS.
Problem Trying to test in Expo Go — it will never load the native model code, wasting hours.
Solution Commit to a dev build from day one. No config plugin is needed (it autolinks), but add the resource-fetcher adapter and push .pte into assetExts in metro.config.js if bundling models.
Loading
Model loading strategies
Concept Three ways to supply a model: bundled via require() (< 512 MB), remote URL (downloaded to the documents dir with progress), or a local file path the user provides.
Example Small classifier? Bundle it. 1 GB LLM? Download from a URL and show downloadProgress (0→1).
Problem Bundling a multi-hundred-MB .pte into the binary bloats the app and hits the bundling size limit.
Solution Prefer remote URL for large models, gate the download behind explicit user opt-in with a visible progress UI, and cache it in the documents directory.
Memory
Model sizing & device RAM
Concept LLMs are RAM-hungry and size scales with parameters and quantization. Rule of thumb: a 1B model ≈ 1 GB download / ~2 GB RAM.
Problem Loading a 3B model on a 4 GB device crashes the app (and the iOS Simulator can't run iOS release builds).
Solution Detect the device tier, start with a small quantized model, and upgrade only when RAM allows. Always test on physical devices.
Lifecycle
LLM lifecycle & crash-safety
Concept A hook auto-loads its model on mount and exposes isReady, downloadProgress, isGenerating, a streaming response, and interrupt(). Only one LLM instance can be active at a time.
Example A "Stop" button calls interrupt(); token emission is batched (~10 tokens / 80ms) so very fast generation doesn't trigger a re-render storm.
Problem Unmounting or navigating away from the screen while the LLM is still generating crashes the app.
Solution Call interrupt() and wait for isGenerating === false before unmounting; bound memory with a sliding-window context strategy and cap generation length (~256 tokens for short answers).
Models
Quantization
Concept Quantization lowers weight precision (e.g. SpinQuant / 8da4w / QLoRA), shrinking the model and speeding inference with minimal quality loss.
Example A base model ~3.3 GB vs. its quantized variant ~1.9 GB — about a 42% reduction — fitting devices that the base model couldn't.
Problem A full-precision model is too large/slow for phones and crashes mid-range devices.
Solution Default to quantized variants and budget tokens/sec on your oldest supported device, not just the newest flagship.
Versioning
Pre-1.0 churn — pin everything
Concept The library is pre-1.0 and ships breaking changes most minor releases; model constants pin to specific tags so the runtime stays compatible.
Example A minor bump renamed factory APIs and hooks (e.g. ImageSegmentation → SemanticSegmentation) and made init mandatory.
Problem Auto-upgrading to "latest" silently breaks the API surface and your model URLs.
Solution Pin the exact version + matching adapter, read release notes before any bump, re-test on physical iOS/Android release builds, and don't hand-edit pinned model URLs.
Pick an answer; it instantly marks it right or wrong and explains why. Your answers are saved in this browser, so you can come back and finish.
Score 0 / 0 answered
Q1What does Time-to-Interactive (TTI) measure?Optimization
TTI is the headline cold-start metric: tap to a screen the user can actually use. It's dominated by JS bundle parse and the work you run before first paint.
Q2Why does Hermes improve startup time?Optimization
Hermes ships bytecode, so there's no parse/compile step at launch — lower TTI and lower memory. It's the default engine under the New Architecture.
Q3A component wrapped in React.memo still re-renders every time. Most likely cause?Optimization
React.memo does a shallow compare; an unstable prop reference defeats it. Stabilize with useMemo/useCallback.
Q4Best key for a list of items that can reorder, insert, or delete?Optimization
Index keys make a recycling list reuse the wrong view on changes (glitches); random keys break identity every render. Use a stable unique id.
Q5How do you keep an animation smooth while the JS thread is busy?Optimization
UI-thread animations keep running even when JS is blocked. Reanimated worklets or useNativeDriver:true move work off the JS thread.
Q6Most common source of a memory leak in a React Native screen?Optimization
Missing cleanup retains references and blocks GC. Always return a cleanup from useEffect: remove listeners, clear intervals, cancel subscriptions.
Q7What's the right first step before optimizing performance?Optimization
Measure before optimizing. Blind memoization adds overhead and often fixes nothing; fix the proven hotspot, then re-measure.
Q8Which approach actually shrinks a large JS bundle?Optimization
Deep specific imports plus sideEffects:false and minify/shrink (R8) strip dead code. Barrel files and side-effects defeat tree-shaking.
Q9A modern recycling list (FlashList v2) requires what?Optimization
v2 uses New-Architecture synchronous layout to auto-measure items, so estimatedItemSize is no longer needed.
Q10Which removes the legacy bridge serialization bottleneck?Optimization
JSI lets JS call native synchronously with no JSON bridge — the foundation of the New Architecture (Fabric + TurboModules).
Q11Heavy work must run after a screen transition without dropping frames. Best tool?Optimization
runAfterInteractions defers work until animations/interactions finish, protecting the frame rate during navigation.
Q12Where do you confirm WHY a component re-rendered?Optimization
The Profiler attributes each re-render to the prop, state, or context change that caused it.
Q13What does 'on-device inference' mean?On-Device AI
Local weights + local compute means privacy (data never leaves the device), offline use, no server cost, and low latency.
Q14Which RN architecture does the on-device AI runtime require?On-Device AI
It ships native code that requires the New Architecture; the old architecture is unsupported.
Q15Why can't you use Expo Go with it?On-Device AI
Native modules can't run in the prebuilt Expo Go sandbox — you need a dev build (expo-dev-client + prebuild/EAS).
Q16What must you call before any model API?On-Device AI
Initialization with a resource-fetcher adapter is mandatory at the app root, or model APIs throw an 'adapter not initialized' error.
Q17Approximate footprint of a 1B-parameter on-device LLM?On-Device AI
Budget storage and RAM carefully. Roughly: 8GB+ devices handle 3B; 6GB handle 1B quantized; 4GB are computer-vision only.
Q18You must leave an LLM screen mid-generation. Correct handling?On-Device AI
Unmounting while generating crashes the app. Stop generation first; only one LLM instance can be active at a time.
Q19Why prefer a quantized model (SpinQuant / 8da4w)?On-Device AI
Quantization lowers weight precision for a big memory/speed win (e.g. ~42% smaller) at minimal quality cost.
Q20Best way to load a multi-hundred-MB model?On-Device AI
Bundling has a <512MB limit and bloats the app. Download large models on demand, show downloadProgress, and cache in the documents dir.
Q21Default hardware backend for most models on both platforms?On-Device AI
CPU (XNNPACK) is the default path; iOS may use Core ML for some models, and Android GPU acceleration is currently limited.
Q22The library is pre-1.0. What's the senior practice?On-Device AI
Breaking changes are routine pre-1.0. Pinned model constants guarantee runtime compatibility — don't hand-edit them or blind-upgrade.
Q23Why does the LLM batch token emissions (~10 tokens / 80ms)?On-Device AI
Generation can exceed 60 tok/s; batching emissions protects the render thread from a flood of state updates.
Q24How do you bound an LLM's context memory?On-Device AI
A sliding-window strategy bounds context; capping generation length (~256 tokens for short answers) keeps memory and latency in check.
A checklist across every requirement in the job description plus your study topics. Tick items as you
feel solid on them — progress is saved in this browser.
0 of 0 complete
🎥 Pitches recorded & reviewed
⚙️ Technical mastery — JD essentials
🏛 Architecture guide topics
🗣 Behavioral & English readiness
✅ Final checks before the call
📱 Optimization & On-Device AI mastery
When this bar hits 100%, you're ready. Good luck, Gerardo — you've done this work for real, now just tell the story. 💪