Agent RulesAgent Rules
Builder
Options
Browse all rules by language and framework
Templates
Pre-built rule sets ready to use
Popular Rules
Top community-ranked rules leaderboard
GuidesAnalyzePricingContact
Builder
OptionsTemplatesPopular Rules
GuidesAnalyzePricingContact

Product

  • Builder
  • Templates
  • Browse Rules
  • My Library

Learn

  • What are AI Agent Rules?
  • Guides
  • FAQ
  • About

Resources

  • Terms
  • Privacy Policy
  • Pricing
  • Contact
  • DMCA Policy

Support

Help keep this project free.

Agent RulesAgent Rules Builder
© 2026 Aurora Algorithm Inc.
Back to Templates

React Native Performance

Performance rules for React Native and Expo applications. Covers 35+ rules across 14 categories: core rendering crash prevention, list virtualization and stable references, GPU-accelerated animations, scroll performance, native navigators, React state patterns, Reanimated shared values, React Compiler compatibility, native UI components, and monorepo conventions.

typescriptTypeScript/react nativeReact Native
react-native
expo
typescript
performance
reanimated
mobile
Customize in Builder

Details

Language
typescriptTypeScript
Framework
react nativeReact Native

Rules Content

AGENTS.md
Edit in Builder

React Native Performance Agent Rules

Core Rendering

- Never use `{value && <Component />}` when value could be an empty string or 0. These are falsy but renderable — React Native will try to render them as bare text, causing a hard crash. Use a ternary with null, explicit boolean coercion with `!!`, or an early return.
- All strings must be wrapped in `<Text>`. React Native crashes if a string is a direct child of `<View>`, including template literals and string concatenation.
- Enable `react/jsx-no-leaked-render` from `eslint-plugin-react` to catch `&&` leaks automatically.

List Performance

- Use a virtualizer like LegendList or FlashList for every scrollable list, even short ones. They render only visible items, reducing memory and mount time. ScrollView renders all children upfront.
- Never `.map()` or `.filter()` data before passing it to a list's `data` prop. Each call creates new references and causes a full re-render on every parent update. Keep the raw data stable and transform inside list items.
- Do not create inline objects inside `renderItem`. Inline objects break `memo()` because they are new references every render. Pass the whole item directly or use individual primitives.
- Define callbacks at the list root with `useCallback` and pass them down. Do not create arrow functions inside `renderItem`.
- Pass primitive props (strings, numbers, booleans) to list item components so `memo()` shallow comparison works correctly.
- Keep list items lightweight. No data fetching, no `useQuery`, no expensive computations, and minimal React Context reads. Use store selectors instead of Context to avoid re-renders on unrelated state changes.
- Use a `type` field on each item and pass `getItemType={(item) => item.type}` to the list. This creates separate recycling pools so a header cell never gets recycled into an image cell.
- Request images at 2x display size from your CDN or image service. Full-resolution images in list cells cause scroll jank and excess memory usage.

Animation

- Only animate `transform` (scale, translate, rotate) and `opacity`. Animating `width`, `height`, `top`, `left`, `margin`, or `padding` triggers a layout pass every frame.
- Use `useDerivedValue` when computing a shared value from another shared value. It is declarative and auto-tracks dependencies. Use `useAnimatedReaction` only for side effects like haptics, logging, or `runOnJS` calls.
- Use `GestureDetector` with `Gesture.Tap()` for animated press states instead of Pressable's `onPressIn`/`onPressOut`. Gesture callbacks run on the UI thread as worklets with no JS bridge round-trip.
- Store the press state (0 or 1) in a shared value and derive the visual (scale, opacity) via `interpolate`.

Scroll Performance

- Never store scroll position in `useState`. Scroll events fire at 60–120 fps and each `setState` triggers a re-render. Use `useSharedValue` with `useAnimatedScrollHandler` for scroll-driven animations. Use `useRef` for tracking position without rendering.

Navigation

- Always use native navigators. Use `@react-navigation/native-stack` or expo-router's default `<Stack>` for stacks. Use native tab implementations for tab bars. Avoid JS-based navigation implementations which are slower.
- Use native header options (`title`, `headerLargeTitleEnabled`, `headerSearchBarOptions`) instead of a custom `header` component. Native headers handle platform-specific behavior automatically.

React State

- Compute derived values during render. Do not store totals, counts, or computed strings in `useState` and sync them with `useEffect`.
- Initialize controlled state as `undefined` and fall back to the server or parent value with `??`. State represents user intent — `undefined` means the user has not interacted yet.
- When new state depends on current state, use the functional updater form `setState(prev => ...)`. Reading state directly in callbacks creates stale closures.

State Architecture

- State variables should represent what is happening (`pressed`, `isOpen`, `progress`), not the visual output (`scale`, `opacity`, `height`). Derive visual values from state via computation or `interpolate`. This lets one state source drive multiple animations and makes debugging simpler.

User Interface

- Use `expo-image` instead of React Native's `Image`. It provides memory-efficient caching, blurhash placeholders, progressive loading, `contentFit`, `priority`, and `cachePolicy`.
- Use native `<Modal presentationStyle="formSheet">` or native form sheets from your navigation library instead of JS-based bottom sheet libraries.
- Use `contentInsetAdjustmentBehavior="automatic"` on the root `<ScrollView>` instead of `<SafeAreaView>` or manual insets.
- Use `contentInset={{ bottom }}` instead of `contentContainerStyle={{ paddingBottom }}` for spacing that changes dynamically. Inset changes do not trigger layout recalculation.
- Use `<Pressable>` instead of deprecated `TouchableOpacity` or `TouchableHighlight`.

Styling

- Add `borderCurve: 'continuous'` to any style that uses `borderRadius` for smooth platform-native corners.
- Apply `gap` on the parent container for sibling spacing instead of `marginBottom` or `marginRight` on each child.
- Use `boxShadow` string syntax instead of legacy shadow objects or `elevation`.
- Limit font sizes to one or two per screen. Use `fontWeight` and grayscale colors for hierarchy instead of varying `fontSize`.
- Use `useLayoutEffect` for synchronous initial measurement and `onLayout` for subsequent changes.

Monorepo

- Install native dependencies inside the app workspace directory, not at the monorepo root. Native packages link to `node_modules` relative to the app directory.
- Keep a single version of every package across the monorepo. Duplicate versions cause multiple React instances, hook errors, and hard-to-diagnose runtime crashes. Enforce with pnpm `overrides` or Yarn `resolutions`.

JavaScript

- Create `Intl.DateTimeFormat` and `Intl.NumberFormat` instances once at module scope. Never construct them inside a render function or inside list `renderItem`.

Fonts

- Load fonts natively at build time via `app.json` assets and `expo-font`. Avoid runtime JS font loading, which causes flash of unstyled text and layout shifts on first render.

Related Templates

typescript

Next.js + TypeScript

Production-ready rules for Next.js applications with TypeScript, App Router, and React Server Components.

typescript

React + TypeScript

Modern React with TypeScript, hooks-first patterns, and component best practices.

typescript

React Performance

Eliminate render waterfalls, reduce bundle size, and optimize server and client rendering in React applications.