All skills

Complete React Native and Expo optimization guide combining Callstack profiling with Vercel code patterns. Covers FPS, TTI, bundle size, memory, lists, animations, state, UI, and React Compiler. Use for any React Native performance, debugging, or best practices task.

Use this Skill: https://skilld.dev/gh/gigs-slc/react-native-skills/react-native

This session only. Nothing lands on disk.

referencesjs-concurrent-react.md

≈1.6k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Skill: Concurrent React

Use useDeferredValue and useTransition to improve perceived performance by prioritizing critical updates.

Quick Pattern

Incorrect (blocks input on every keystroke):

const [query, setQuery] = useState('');
<TextInput value={query} onChangeText={setQuery} />
<ExpensiveList query={query} />  // Blocks typing

Correct (input stays responsive):

const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
<TextInput value={query} onChangeText={setQuery} />
<ExpensiveList query={deferredQuery} />  // Deferred update

When to Use

  • Search/filter inputs feel laggy with large result sets
  • Expensive computations block UI interactions
  • Loading states appear too frequently
  • Want to show stale content while loading new content
  • Need to prioritize user input over background updates

Prerequisites

  • React Native with New Architecture enabled (default in RN 0.76+)
  • React 18+ features (useDeferredValue, useTransition, Suspense)

Concept Overview

Concurrent React allows updates to be:

  • Paused: Low-priority work can wait
  • Interrupted: User input takes priority
  • Abandoned: Outdated updates can be skipped

Step-by-Step Instructions

Pattern 1: Defer Expensive Rendering with useDeferredValue

Use when a value drives expensive computation but you want input to stay responsive.

import { useState, useDeferredValue } from 'react';

const SearchScreen = () => {
  const [query, setQuery] = useState('');
  const deferredQuery = useDeferredValue(query);
  
  // query updates immediately (input stays responsive)
  // deferredQuery updates when React has time
  
  return (
    <View>
      <TextInput
        value={query}
        onChangeText={setQuery}
        placeholder="Search..."
      />
      {/* ExpensiveList receives deferred value */}
      <ExpensiveList query={deferredQuery} />
    </View>
  );
};

Pattern 2: Show Stale Content While Loading

const SearchWithStaleIndicator = () => {
  const [query, setQuery] = useState('');
  const deferredQuery = useDeferredValue(query);
  const isStale = query !== deferredQuery;
  
  return (
    <View>
      <TextInput value={query} onChangeText={setQuery} />
      <View style={isStale && { opacity: 0.7 }}>
        <SearchResults query={deferredQuery} />
      </View>
      {isStale && <ActivityIndicator />}
    </View>
  );
};

Pattern 3: Transition Non-Critical Updates with useTransition

Use when you have multiple state updates and want to mark some as low-priority.

import { useState, useTransition } from 'react';

const TransitionExample = () => {
  const [count, setCount] = useState(0);
  const [heavyData, setHeavyData] = useState(null);
  const [isPending, startTransition] = useTransition();
  
  const handleIncrement = () => {
    // High priority - updates immediately
    setCount(c => c + 1);
    
    // Low priority - can be interrupted
    startTransition(() => {
      setHeavyData(computeExpensiveData());
    });
  };
  
  return (
    <View>
      <Text>Count: {count}</Text>
      {isPending ? <ActivityIndicator /> : <HeavyComponent data={heavyData} />}
      <Button onPress={handleIncrement} title="Increment" />
    </View>
  );
};

Pattern 4: Suspense for Data Fetching

import { Suspense, useDeferredValue } from 'react';

const DataScreen = () => {
  const [query, setQuery] = useState('');
  const deferredQuery = useDeferredValue(query);
  
  return (
    <View>
      <TextInput value={query} onChangeText={setQuery} />
      <Suspense fallback={<LoadingSpinner />}>
        <SearchResults query={deferredQuery} />
      </Suspense>
    </View>
  );
};

Code Examples

Slow Component Optimization

// Without Concurrent React - UI freezes
const SlowSearch = () => {
  const [query, setQuery] = useState('');
  
  return (
    <>
      <TextInput value={query} onChangeText={setQuery} />
      <SlowComponent query={query} /> {/* Blocks every keystroke */}
    </>
  );
};

// With Concurrent React - UI stays responsive  
const FastSearch = () => {
  const [query, setQuery] = useState('');
  const deferredQuery = useDeferredValue(query);
  
  return (
    <>
      <TextInput value={query} onChangeText={setQuery} />
      <SlowComponent query={deferredQuery} />
    </>
  );
};

// Important: Wrap SlowComponent in memo to prevent re-renders from parent
const SlowComponent = memo(({ query }) => {
  // Expensive computation here
});

Automatic Batching (React 18+)

React 18 automatically batches state updates:

// Before React 18 - 2 re-renders
setTimeout(() => {
  setCount(c => c + 1);
  setFlag(f => !f);
  // Rendered twice
}, 1000);

// React 18+ - 1 re-render (automatic batching)
setTimeout(() => {
  setCount(c => c + 1);
  setFlag(f => !f);
  // Rendered once!
}, 1000);

When to Use Which

Scenario Solution
Single value drives expensive render useDeferredValue
Multiple state updates, some non-critical useTransition
Need loading indicator for transition useTransition (has isPending)
Data fetching with loading states Suspense + useDeferredValue
Simple parent-to-child value deferral useDeferredValue

Important Considerations

  1. Wrap expensive components in memo(): Without memoization, the component re-renders from parent anyway.

  2. Use with New Architecture: Concurrent features require New Architecture in React Native.

  3. Don't overuse: Only defer truly expensive work. Adding complexity for fast components is counterproductive.

Common Pitfalls

  • Forgetting memo(): useDeferredValue is useless if child re-renders from parent
  • Using for simple state: Overhead isn't worth it for cheap updates
  • Expecting faster computation: These hooks don't make code faster, they prioritize what runs when

Related Skills

Source: SKILL.md on GitHub

2 alerts6mo4 checks · Risk HIGH
  • Gen Agent Trust Hub7mo

    The skill is a technical React Native guide that includes a high-risk remote code execution pattern for installing a performance tool.

  • Socket6mo

    No alerts

  • Snyk7mo

    Risk: MEDIUM · No issues

  • Runlayer7mo

    7/67 files flagged

Signed by skilld at 1d299ca. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 days ago.

Dormantupdated 8 months ago
Other metadata
metadata
{
  "author": "Callstack + Vercel",
  "version": "1.0.0",
  "tags": "react-native, expo, performance, optimization, patterns"
}

README badge

README badge for gigs-slc/react-native-skills/react-native