All skills
callstackincubator avatar

/react-native-best-practices

@fa0bad0 official

Provides React Native performance optimization guidelines for FPS, TTI, bundle size, memory leaks, re-renders, and animations. Applies to tasks involving Hermes optimization, JS thread blocking, bridge overhead, FlashList, native modules, or debugging jank and frame drops.

Use this Skill: https://skilld.dev/gh/callstackincubator/agent-skills/react-native-best-practices

This session only. Nothing lands on disk.

referencesnative-memory-patterns.md

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

Skill: Native Memory Management

Understand memory management patterns in C++, Swift, and Kotlin for React Native native modules.

Quick Reference

Pattern Languages Mechanism
Reference Counting Swift, Obj-C Count refs, free at zero
Smart pointers C++ Ownership encoded in pointer type
Garbage Collection Kotlin/Java, JavaScript GC scans and frees unreachable
Manual C, C++ (raw pointers) Explicit new/delete

Key rule: Prefer stack allocation or std::unique_ptr for single ownership; use std::shared_ptr only for real shared ownership and std::weak_ptr to break cycles. In Swift, use weak when the referenced object can disappear first; use unowned only when its lifetime is guaranteed to be at least as long.

When to Use

  • Writing native modules with manual memory management
  • Debugging native memory leaks
  • Interfacing C++ with Swift/Kotlin
  • Understanding reference counting vs garbage collection

C++ Smart Pointers

std::unique_ptr - Single Owner

#include <memory>

void takeOwnership(std::unique_ptr<std::string> s) {
    std::cout << *s;
    // Automatically deleted when function ends
}

int main() {
    auto str = std::make_unique<std::string>("Hello");
    
    // Can only be moved, not copied
    takeOwnership(std::move(str));
    // str is now empty
    
    return 0;
}

std::shared_ptr - Multiple Owners

void useShared(std::shared_ptr<std::string> s) {
    std::cout << *s;  // Reference count temporarily +1
}

void useReference(const std::shared_ptr<std::string>& s) {
    std::cout << *s;  // No ref count change (passed by reference)
}

int main() {
    auto str = std::make_shared<std::string>("Hello");
    
    useShared(str);      // Copies pointer, ref count +1
    useReference(str);   // No copy, ref count unchanged
    
    std::cout << *str;   // Still valid
    return 0;
}

std::weak_ptr - Non-Owning Reference

void useWeak(std::weak_ptr<std::string> weak) {
    if (auto shared = weak.lock()) {  // Check if still exists
        std::cout << *shared;
    } else {
        std::cout << "Object destroyed";
    }
}

int main() {
    auto str = std::make_shared<std::string>("Hello");
    std::weak_ptr<std::string> weak = str;  // No ref count increase
    
    useWeak(weak);  // Works
    str.reset();    // Destroys object
    useWeak(weak);  // "Object destroyed"
    
    return 0;
}

Swift ARC (Automatic Reference Counting)

class Person {
    let name: String
    init(name: String) { self.name = name }
    deinit { print("Deallocated") }
}

do {
    let person1 = Person(name: "John")  // Ref count: 1
    
    do {
        let person2 = person1  // Ref count: 2
    }  // person2 out of scope, ref count: 1
    
}  // person1 out of scope, ref count: 0, "Deallocated"

Breaking Reference Cycles with weak

// BAD: Reference cycle (memory leak)
class A {
    var b: B?
}
class B {
    var a: A?  // Strong reference creates cycle
}

// GOOD: Use weak to break cycle
class A {
    var b: B?
}
class B {
    weak var a: A?  // Weak reference, doesn't prevent deallocation
}

Kotlin/Android GC

Weak References for Caches

WeakHashMap weakens keys, not values. Store WeakReference values explicitly when the cached value itself should not be strongly retained. Do not rely on deterministic System.gc() behavior in tests.

WeakReference for Callbacks

class DataManager {
    // Weak references to listeners prevent memory leaks
    private val listeners = mutableListOf<WeakReference<DataListener>>()
    
    fun addListener(listener: DataListener) {
        listeners.add(WeakReference(listener))
    }
    
    fun notifyListeners(data: String) {
        listeners.forEach { ref ->
            ref.get()?.onDataChanged(data)
        }
    }
}

Common Memory Leak Sources

1. Forgetting to Delete (C++)

// BAD: Memory leak
int main() {
    std::string* str = new std::string("Hello");
    // Forgot to delete!
    return 0;
}

// GOOD: Use smart pointers or stack allocation
int main() {
    auto str = std::make_unique<std::string>("Hello");
    // Automatically deleted
    return 0;
}

2. Reference Cycles (Swift/C++)

// BAD: Cycle
class A { std::shared_ptr<B> b; };
class B { std::shared_ptr<A> a; };

// GOOD: Break with weak_ptr
class A { std::shared_ptr<B> b; };
class B { std::weak_ptr<A> a; };

3. Unremoved Listeners (Kotlin)

// BAD: Listener never removed
class MyClass {
    private val listener = object : Callback {
        override fun onEvent() { /* ... */ }
    }
    
    init {
        EventManager.addListener(listener)
        // Never removed!
    }
}

// GOOD: Implement cleanup
class MyClass : AutoCloseable {
    private val listener = object : Callback {
        override fun onEvent() { /* ... */ }
    }
    
    init {
        EventManager.addListener(listener)
    }
    
    override fun close() {
        EventManager.removeListener(listener)
    }
}

Swift Unmanaged (Advanced)

Use Unmanaged only for C interop that explicitly transfers ownership. Match passRetained with takeRetainedValue, and passUnretained with takeUnretainedValue.

Best Practices Summary

Language Best Practice
C++ Prefer stack or unique_ptr; use shared_ptr only for shared ownership
Swift Use weak for delegates and disappearing references; use unowned only with guaranteed lifetime
Kotlin Implement AutoCloseable, use WeakReference
All Prefer stack over heap when possible

Related Skills

Source: SKILL.md on GitHub

1 alert17d5 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    This skill provides a comprehensive performance optimization guide for React Native applications. It contains standard developer workflows using command-line tools and patterns for advanced techniques like remote code splitting, which include detailed security hardening advice.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: LOW · No issues

  • Runlayer7mo

    11/31 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

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

Last checked against GitHub 2 weeks ago.

Activeupdated 2 months ago
  • Performance
  • react-native
  • optimization
  • profiling
  • fps
  • bundle-size
  • memory
  • hermes
  • flatlist
  • animations

README badge

README badge for callstackincubator/agent-skills/react-native-best-practices

Provides React Native performance optimization guidelines covering FPS, TTI, bundle size, memory leaks, re-renders, and animations. Includes reference documentation for Hermes, FlashList, Turbo Modules, React Compiler, Reanimated, and profiling with Xcode and Android Studio.

Generated from the current SKILL.md.

Does this skill cover Expo apps?
Yes. The guidelines apply to both bare React Native and Expo projects. Expo SDK 52+ supports tree shaking and Re.Pack code splitting.
What performance metrics should I measure first?
Start with FPS (use React Native DevTools), Time To Interactive (TTI), bundle size, and memory growth. The skill emphasizes measuring baseline metrics before and after optimization to validate improvements.
Does this cover Hermes optimization?
Yes. The skill includes Hermes-specific guidance such as disabling JS bundle compression on Android to enable mmap, and checking Hermes API coverage before removing polyfills.
What if I'm using a list library other than FlatList or FlashList?
The skill prioritizes FlatList and FlashList as virtualized replacements for ScrollView. It includes library version checks (e.g., FlashList v2 API changes) but focuses on these two libraries.
Does this include native profiling guidance?
Yes. The skill covers profiling with Xcode Instruments (iOS) and Android Studio CPU Profiler, plus guidance on native threading, Turbo Modules, and C++ performance-critical code.

Generated from the current SKILL.md. These answers refresh after source changes.