mobile-ai-agents 1.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +228 -0
- package/CLAUDE.md +236 -0
- package/LICENSE +21 -0
- package/README.md +652 -0
- package/agents/android/android-crash-analyzer/README.md +134 -0
- package/agents/android/android-crash-analyzer/agent.md +206 -0
- package/agents/android/android-crash-analyzer/example-input.md +138 -0
- package/agents/android/android-crash-analyzer/example-output.md +225 -0
- package/agents/android/anr-investigation/README.md +78 -0
- package/agents/android/anr-investigation/agent.md +117 -0
- package/agents/android/anr-investigation/example-input.md +62 -0
- package/agents/android/anr-investigation/example-output.md +103 -0
- package/agents/android/axiom/agent.md +197 -0
- package/agents/android/code-reviewer/README.md +108 -0
- package/agents/android/code-reviewer/agent.md +210 -0
- package/agents/android/code-reviewer/example-input.md +116 -0
- package/agents/android/code-reviewer/example-output.md +115 -0
- package/agents/android/compose-navigation/README.md +76 -0
- package/agents/android/compose-navigation/agent.md +121 -0
- package/agents/android/compose-navigation/example-input.md +49 -0
- package/agents/android/compose-navigation/example-output.md +325 -0
- package/agents/android/compose-screen-builder/README.md +95 -0
- package/agents/android/compose-screen-builder/agent.md +170 -0
- package/agents/android/compose-screen-builder/example-input.md +40 -0
- package/agents/android/compose-screen-builder/example-output.md +568 -0
- package/agents/android/compose-ui-reviewer/README.md +73 -0
- package/agents/android/compose-ui-reviewer/agent.md +253 -0
- package/agents/android/compose-ui-reviewer/example-input.md +84 -0
- package/agents/android/compose-ui-reviewer/example-output.md +102 -0
- package/agents/android/crash-analyzer/README.md +53 -0
- package/agents/android/crash-analyzer/agent.md +295 -0
- package/agents/android/memory-leak-analyzer/README.md +79 -0
- package/agents/android/memory-leak-analyzer/agent.md +116 -0
- package/agents/android/memory-leak-analyzer/example-input.md +78 -0
- package/agents/android/memory-leak-analyzer/example-output.md +128 -0
- package/agents/cross-platform/accessibility-auditor/README.md +47 -0
- package/agents/cross-platform/accessibility-auditor/agent.md +268 -0
- package/agents/cross-platform/accessibility-auditor/example-input.md +84 -0
- package/agents/cross-platform/accessibility-auditor/example-output.md +132 -0
- package/agents/cross-platform/appforge/agent.md +303 -0
- package/agents/cross-platform/ci-cd-generator/README.md +65 -0
- package/agents/cross-platform/ci-cd-generator/agent.md +422 -0
- package/agents/cross-platform/ci-cd-generator/example-input.md +69 -0
- package/agents/cross-platform/ci-cd-generator/example-output.md +261 -0
- package/agents/cross-platform/crasher/agent.md +221 -0
- package/agents/cross-platform/figma/agent.md +247 -0
- package/agents/cross-platform/launchpad/agent.md +330 -0
- package/agents/cross-platform/mobile-harness/agent.md +422 -0
- package/agents/cross-platform/mobile-memory/agent.md +429 -0
- package/agents/cross-platform/perf/agent.md +261 -0
- package/agents/cross-platform/pipeline/agent.md +288 -0
- package/agents/cross-platform/release-notes-generator/README.md +63 -0
- package/agents/cross-platform/release-notes-generator/agent.md +218 -0
- package/agents/cross-platform/release-notes-generator/example-input.md +71 -0
- package/agents/cross-platform/release-notes-generator/example-output.md +96 -0
- package/agents/cross-platform/scribe/agent.md +180 -0
- package/agents/cross-platform/security-scanner/README.md +61 -0
- package/agents/cross-platform/security-scanner/agent.md +287 -0
- package/agents/cross-platform/security-scanner/example-input.md +77 -0
- package/agents/cross-platform/security-scanner/example-output.md +141 -0
- package/agents/cross-platform/sentinel/agent.md +217 -0
- package/agents/cross-platform/store-listing-writer/README.md +58 -0
- package/agents/cross-platform/store-listing-writer/agent.md +380 -0
- package/agents/cross-platform/store-listing-writer/example-input.md +67 -0
- package/agents/cross-platform/store-listing-writer/example-output.md +131 -0
- package/agents/flutter/bloc-feature-builder/README.md +101 -0
- package/agents/flutter/bloc-feature-builder/agent.md +225 -0
- package/agents/flutter/bloc-feature-builder/example-input.md +47 -0
- package/agents/flutter/bloc-feature-builder/example-output.md +838 -0
- package/agents/flutter/dart/agent.md +223 -0
- package/agents/flutter/widget-generator/README.md +66 -0
- package/agents/flutter/widget-generator/agent.md +264 -0
- package/agents/flutter/widget-generator/example-input.md +71 -0
- package/agents/flutter/widget-generator/example-output.md +163 -0
- package/agents/gaming/forge/agent.md +197 -0
- package/agents/gaming/unreal/agent.md +200 -0
- package/agents/ios/crash-analyzer/README.md +69 -0
- package/agents/ios/crash-analyzer/agent.md +300 -0
- package/agents/ios/crash-analyzer/example-input.md +83 -0
- package/agents/ios/crash-analyzer/example-output.md +126 -0
- package/agents/ios/swift/agent.md +206 -0
- package/agents/ios/swift-reviewer/README.md +68 -0
- package/agents/ios/swift-reviewer/agent.md +231 -0
- package/agents/ios/swift-reviewer/example-input.md +100 -0
- package/agents/ios/swift-reviewer/example-output.md +127 -0
- package/agents/react-native/bridge/agent.md +212 -0
- package/agents/react-native/performance-optimizer/README.md +81 -0
- package/agents/react-native/performance-optimizer/agent.md +284 -0
- package/agents/react-native/performance-optimizer/example-input.md +104 -0
- package/agents/react-native/performance-optimizer/example-output.md +132 -0
- package/agents/unity/shader-generator/README.md +77 -0
- package/agents/unity/shader-generator/agent.md +270 -0
- package/agents/unity/shader-generator/example-input.md +70 -0
- package/agents/unity/shader-generator/example-output.md +160 -0
- package/agents/unreal/blueprint-advisor/README.md +71 -0
- package/agents/unreal/blueprint-advisor/agent.md +311 -0
- package/agents/unreal/blueprint-advisor/example-input.md +73 -0
- package/agents/unreal/blueprint-advisor/example-output.md +217 -0
- package/cli/index.js +1091 -0
- package/docs/agent-guide.md +138 -0
- package/docs/chatgpt-integration.md +219 -0
- package/docs/core-loops.md +143 -0
- package/docs/cursor-integration.md +143 -0
- package/docs/getting-started.md +132 -0
- package/docs/index.html +711 -0
- package/docs/installation.md +271 -0
- package/docs/mobile-harness.md +160 -0
- package/docs/mobile-mcp.md +172 -0
- package/docs/mobile-memory.md +349 -0
- package/docs/release-process.md +85 -0
- package/docs/releases/release-v1.0.0.md +165 -0
- package/docs/roadmap/github-issues.md +239 -0
- package/docs/skill-categories.md +125 -0
- package/docs/vscode-copilot-integration.md +104 -0
- package/docs/wiki.md +615 -0
- package/install.sh +507 -0
- package/mobile-karpathy.md +79 -0
- package/package.json +57 -0
- package/skills/android/README.md +31 -0
- package/skills/android/android-tdd.md +89 -0
- package/skills/android/anr-investigation.md +251 -0
- package/skills/android/code-review.md +98 -0
- package/skills/android/compose-migration.md +48 -0
- package/skills/android/compose-review.md +78 -0
- package/skills/android/kotlin-modernize.md +51 -0
- package/skills/android/memory-leak-investigation.md +256 -0
- package/skills/android/proguard-rules.md +48 -0
- package/skills/cross-platform/accessibility-audit.md +63 -0
- package/skills/cross-platform/api-versioning.md +59 -0
- package/skills/cross-platform/clean-code-audit.md +239 -0
- package/skills/cross-platform/crash-triage.md +53 -0
- package/skills/cross-platform/deeplink-debug.md +57 -0
- package/skills/cross-platform/feature-slice.md +48 -0
- package/skills/cross-platform/grill-mobile.md +64 -0
- package/skills/cross-platform/mobile-mcp-qa.md +193 -0
- package/skills/cross-platform/mobile-memory-graph.md +179 -0
- package/skills/cross-platform/mobile-memory-save.md +210 -0
- package/skills/cross-platform/mobile-memory-search.md +154 -0
- package/skills/cross-platform/perf-audit.md +61 -0
- package/skills/cross-platform/prd-verification.md +324 -0
- package/skills/cross-platform/release-prep.md +64 -0
- package/skills/cross-platform/security-audit.md +281 -0
- package/skills/cross-platform/store-listing.md +75 -0
- package/skills/flutter/README.md +32 -0
- package/skills/flutter/dart-modernize.md +47 -0
- package/skills/flutter/flutter-review.md +59 -0
- package/skills/flutter/flutter-tdd.md +73 -0
- package/skills/flutter/widget-extract.md +41 -0
- package/skills/flutter/widget-gen.md +131 -0
- package/skills/gaming/blueprint-to-cpp.md +51 -0
- package/skills/gaming/game-perf.md +54 -0
- package/skills/gaming/shader-gen.md +44 -0
- package/skills/gaming/unity-tdd.md +85 -0
- package/skills/ios/README.md +45 -0
- package/skills/ios/data-persistence.md +151 -0
- package/skills/ios/ios-tdd.md +90 -0
- package/skills/ios/networking.md +139 -0
- package/skills/ios/performance.md +122 -0
- package/skills/ios/swift-concurrency.md +57 -0
- package/skills/ios/swift-review.md +124 -0
- package/skills/ios/swiftui-review.md +49 -0
- package/skills/ios/swiftui-state.md +122 -0
- package/skills/ios/unit-testing.md +144 -0
- package/skills/ios/xcode-warnings.md +37 -0
- package/skills/react-native/README.md +42 -0
- package/skills/react-native/bridge-audit.md +104 -0
- package/skills/react-native/expo-optimize.md +55 -0
- package/skills/react-native/new-arch-migrate.md +53 -0
- package/skills/react-native/performance.md +124 -0
- package/skills/react-native/rn-review.md +53 -0
- package/skills/react-native/rn-tdd.md +76 -0
- package/skills/shared/README.md +46 -0
- package/skills/shared/accessibility-audit.md +132 -0
- package/skills/shared/crash-analysis.md +110 -0
- package/skills/shared/security-scan.md +149 -0
- package/skills/unity/README.md +31 -0
- package/skills/unity/shader-review.md +110 -0
- package/templates/agent-template.md +88 -0
- package/templates/prompt-template.md +50 -0
- package/templates/skill-template.md +64 -0
- package/templates/workflow-template.md +48 -0
- package/workflows/app-launch.md +66 -0
- package/workflows/appforge-workflow.md +232 -0
- package/workflows/ci-setup.md +77 -0
- package/workflows/crash-to-fix.md +71 -0
- package/workflows/feature-ship.md +61 -0
- package/workflows/game-level.md +72 -0
- package/workflows/mobile-harness.md +319 -0
- package/workflows/mobile-mcp-qa.md +228 -0
- package/workflows/mobile-memory-workflow.md +243 -0
- package/workflows/new-project-setup.md +93 -0
- package/workflows/new-screen.md +68 -0
- package/workflows/perf-sprint.md +78 -0
- package/workflows/release-cycle.md +71 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Example Output — iOS Swift Code Reviewer
|
|
2
|
+
|
|
3
|
+
Full agent response to the input in [`example-input.md`](example-input.md).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
REVIEW SUMMARY
|
|
9
|
+
==============
|
|
10
|
+
File: Sources/Profile/ProfileViewModel.swift
|
|
11
|
+
Layer: ViewModel
|
|
12
|
+
Issues Found: 5
|
|
13
|
+
Critical: 3 Warning: 2 Info: 0
|
|
14
|
+
|
|
15
|
+
FINDINGS
|
|
16
|
+
--------
|
|
17
|
+
|
|
18
|
+
[CRITICAL] Line 38 — Strong self capture in fetchUser completion (retain cycle + threading)
|
|
19
|
+
Problem : The closure captures `self` strongly with no capture list. If `ProfileService`
|
|
20
|
+
retains the completion block (standard for async operations), a retain cycle
|
|
21
|
+
forms: ViewModel → Service → completion → ViewModel. Neither will be deallocated.
|
|
22
|
+
Additionally, the callback fires on `DispatchQueue.global()`, but `self.user = user`
|
|
23
|
+
mutates a `@Published` property — this must happen on the Main thread or it causes
|
|
24
|
+
a data race and undefined behavior in SwiftUI.
|
|
25
|
+
Fix :
|
|
26
|
+
service.fetchUser(id: id) { [weak self] result in
|
|
27
|
+
guard let self else { return }
|
|
28
|
+
DispatchQueue.main.async {
|
|
29
|
+
switch result {
|
|
30
|
+
case .success(let user): self.user = user
|
|
31
|
+
case .failure(let error): self.error = error.localizedDescription
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
Better: migrate to async/await (see INFO below).
|
|
36
|
+
|
|
37
|
+
[CRITICAL] Line 46 — Force unwrap on jpegData(compressionQuality:)
|
|
38
|
+
Problem : `UIImage.jpegData(compressionQuality:)` returns `Data?` — it can return nil
|
|
39
|
+
for image formats that cannot be JPEG-encoded (some CGImage configurations)
|
|
40
|
+
or under memory pressure. The `!` will crash at runtime with:
|
|
41
|
+
"Unexpectedly found nil while implicitly unwrapping an Optional value."
|
|
42
|
+
Fix :
|
|
43
|
+
guard let data = image.jpegData(compressionQuality: 0.8) else {
|
|
44
|
+
self.error = "Failed to encode image for upload"
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
Note: also prefer 0.8 compression quality over 1.0 to reduce upload size and memory.
|
|
48
|
+
|
|
49
|
+
[CRITICAL] Line 47 — [unowned self] in escaping upload completion (crash after dealloc)
|
|
50
|
+
Problem : `[unowned self]` does NOT nil-check before access. If the ViewModel is
|
|
51
|
+
deallocated before the upload callback fires (e.g., user dismisses the screen),
|
|
52
|
+
accessing `self` via an unowned reference causes an EXC_BAD_ACCESS crash.
|
|
53
|
+
Network callbacks are inherently async — the ViewModel cannot guarantee it
|
|
54
|
+
outlives them.
|
|
55
|
+
Fix :
|
|
56
|
+
service.upload(data: data) { [weak self] success in
|
|
57
|
+
guard let self else { return }
|
|
58
|
+
if success { self.user?.avatarUpdated = true }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
[WARNING] Line 35 — Concrete ProfileService type (not injectable, not testable)
|
|
62
|
+
Problem : `let service = ProfileService()` constructs a concrete dependency directly.
|
|
63
|
+
Unit-testing ProfileViewModel requires hitting the real ProfileService (and
|
|
64
|
+
its network calls). There is no way to inject a mock.
|
|
65
|
+
Fix : Declare the service using the protocol type and inject via initializer:
|
|
66
|
+
private let service: ProfileServiceProtocol
|
|
67
|
+
|
|
68
|
+
init(service: ProfileServiceProtocol = ProfileService()) {
|
|
69
|
+
self.service = service
|
|
70
|
+
}
|
|
71
|
+
Now tests can pass MockProfileService(). The default argument keeps callsites unchanged.
|
|
72
|
+
|
|
73
|
+
[WARNING] Lines 38–44 — Completion-handler API should be migrated to async/await
|
|
74
|
+
Problem : Completion handlers are the legacy Swift concurrency model. async/await:
|
|
75
|
+
- Eliminates the retain cycle risk in closures
|
|
76
|
+
- Handles `@MainActor` automatically when the ViewModel is annotated
|
|
77
|
+
- Supports structured cancellation
|
|
78
|
+
- Is significantly more readable
|
|
79
|
+
Fix :
|
|
80
|
+
@MainActor
|
|
81
|
+
class ProfileViewModel: ObservableObject {
|
|
82
|
+
@Published var user: User?
|
|
83
|
+
@Published var error: String?
|
|
84
|
+
private let service: ProfileServiceProtocol
|
|
85
|
+
|
|
86
|
+
init(service: ProfileServiceProtocol = ProfileService()) {
|
|
87
|
+
self.service = service
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
func loadUser(id: String) async {
|
|
91
|
+
do {
|
|
92
|
+
user = try await service.fetchUser(id: id)
|
|
93
|
+
} catch {
|
|
94
|
+
self.error = error.localizedDescription
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
func uploadAvatar(image: UIImage) async {
|
|
99
|
+
guard let data = image.jpegData(compressionQuality: 0.8) else {
|
|
100
|
+
error = "Failed to encode image"
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
let success = try? await service.upload(data: data)
|
|
104
|
+
if success == true { user?.avatarUpdated = true }
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
MEMORY SAFETY
|
|
109
|
+
-------------
|
|
110
|
+
Retain cycles detected: Yes
|
|
111
|
+
→ Strong self capture in fetchUser completion (line 38).
|
|
112
|
+
unowned misuse detected: Yes
|
|
113
|
+
→ [unowned self] in upload callback (line 47) — can crash after ViewModel dealloc.
|
|
114
|
+
|
|
115
|
+
CONCURRENCY
|
|
116
|
+
-----------
|
|
117
|
+
Actor isolation issues: Yes
|
|
118
|
+
→ @Published properties mutated on DispatchQueue.global() background thread (lines 40–41).
|
|
119
|
+
Add @MainActor to the class or dispatch mutations explicitly to the main queue.
|
|
120
|
+
Sendable conformance gaps: No
|
|
121
|
+
|
|
122
|
+
TESTABILITY SCORE: 3/10
|
|
123
|
+
→ Concrete service type and completion-handler API make unit testing require real network calls.
|
|
124
|
+
After applying the warning fixes, testability rises to ~8/10.
|
|
125
|
+
|
|
126
|
+
OVERALL VERDICT: NEEDS WORK
|
|
127
|
+
```
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# BRIDGE — React Native Optimizer
|
|
2
|
+
|
|
3
|
+
**Platform:** React Native (JSI / New Architecture)
|
|
4
|
+
**Personality:** JSI evangelist. Tracks every bridge crossing like a border guard. New Architecture or nothing.
|
|
5
|
+
**Category:** Performance / Architecture
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Reviews React Native components and modules for bridge call bottlenecks, re-render inefficiencies, New Architecture readiness, and JS thread blockage. Returns a structured findings report with severity, location, and a concrete fix for every issue.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Input Format
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
PLATFORM: React Native
|
|
19
|
+
RN_VERSION: <e.g. 0.73>
|
|
20
|
+
ARCHITECTURE: <old | new | unknown>
|
|
21
|
+
FILE_PATH: <relative path>
|
|
22
|
+
CODE:
|
|
23
|
+
<paste the component or module>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Output Format
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
BRIDGE REVIEW
|
|
32
|
+
=============
|
|
33
|
+
File: <path>
|
|
34
|
+
Component Type: <Screen | Component | Hook | NativeModule | ...>
|
|
35
|
+
Issues Found: <count> Critical: <n> Warning: <n> Info: <n>
|
|
36
|
+
|
|
37
|
+
FINDINGS
|
|
38
|
+
--------
|
|
39
|
+
[CRITICAL] Line N — <title>
|
|
40
|
+
Problem : <what is wrong and why it matters>
|
|
41
|
+
Fix : <concrete corrected code>
|
|
42
|
+
|
|
43
|
+
[WARNING] Line N — <title>
|
|
44
|
+
Problem : <what is wrong>
|
|
45
|
+
Fix : <corrected approach>
|
|
46
|
+
|
|
47
|
+
[INFO] Line N — <title>
|
|
48
|
+
Problem : <suggestion>
|
|
49
|
+
Fix : <improvement>
|
|
50
|
+
|
|
51
|
+
BRIDGE CROSSING REPORT
|
|
52
|
+
-----------------------
|
|
53
|
+
Synchronous bridge calls: <count>
|
|
54
|
+
→ <list of locations>
|
|
55
|
+
Bridge calls in render path: Yes / No
|
|
56
|
+
→ <explanation>
|
|
57
|
+
|
|
58
|
+
RE-RENDER ANALYSIS
|
|
59
|
+
------------------
|
|
60
|
+
Missing memoization: Yes / No
|
|
61
|
+
→ <locations>
|
|
62
|
+
Prop drilling detected: Yes / No
|
|
63
|
+
|
|
64
|
+
NEW ARCHITECTURE READINESS: <Ready | Needs Work | Not Compatible>
|
|
65
|
+
→ <explanation>
|
|
66
|
+
|
|
67
|
+
VERDICT: PASS / NEEDS WORK / REWRITE
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## System Prompt
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
You are BRIDGE — a React Native performance expert who has profiled hundreds of apps with
|
|
76
|
+
Flipper and Systrace. You know that every synchronous bridge call is a tax on the JS thread,
|
|
77
|
+
that a missing useMemo on an expensive list is a frame drop waiting to happen, and that
|
|
78
|
+
running on the Old Architecture in 2025 is technical debt that compounds daily.
|
|
79
|
+
|
|
80
|
+
Review the provided React Native source for:
|
|
81
|
+
1. Bridge calls in hot paths: any NativeModule call, AsyncStorage, or Animated.Value
|
|
82
|
+
updates inside render or tight loops.
|
|
83
|
+
2. Re-renders: missing React.memo, missing useMemo/useCallback on expensive computations
|
|
84
|
+
or handler functions passed as props.
|
|
85
|
+
3. JS thread blockage: synchronous operations, large JSON.parse/stringify in render,
|
|
86
|
+
Array methods on large datasets without virtualization.
|
|
87
|
+
4. New Architecture readiness: Old Architecture NativeModule patterns (RCTBridgeModule),
|
|
88
|
+
Animated.event without useNativeDriver, missing TurboModule annotations.
|
|
89
|
+
5. FlatList/SectionList: missing keyExtractor, getItemLayout, removeClippedSubviews,
|
|
90
|
+
non-virtualized lists for > 20 items.
|
|
91
|
+
6. State management: unnecessary setState causing full-tree re-renders, Context triggers.
|
|
92
|
+
7. Navigation: heavy components mounted in tab navigators before they are needed.
|
|
93
|
+
|
|
94
|
+
Severity:
|
|
95
|
+
- CRITICAL: causes jank > 16ms frames, crashes, or bridge thread starvation
|
|
96
|
+
- WARNING: unnecessary re-renders, bridge overhead, technical debt
|
|
97
|
+
- INFO: minor optimization, style, New Architecture opportunity
|
|
98
|
+
|
|
99
|
+
Output MUST follow the exact format specified. Do not add extra sections or omit any section.
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Example
|
|
105
|
+
|
|
106
|
+
### Input
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
PLATFORM: React Native
|
|
110
|
+
RN_VERSION: 0.73
|
|
111
|
+
ARCHITECTURE: old
|
|
112
|
+
FILE_PATH: src/screens/FeedScreen.tsx
|
|
113
|
+
CODE:
|
|
114
|
+
export default function FeedScreen() {
|
|
115
|
+
const [posts, setPosts] = useState<Post[]>([]);
|
|
116
|
+
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
AsyncStorage.getItem('cached_posts').then(data => {
|
|
119
|
+
if (data) setPosts(JSON.parse(data));
|
|
120
|
+
});
|
|
121
|
+
fetchPosts().then(setPosts);
|
|
122
|
+
}, []);
|
|
123
|
+
|
|
124
|
+
const renderItem = ({ item }: { item: Post }) => (
|
|
125
|
+
<PostCard post={item} onLike={() => handleLike(item.id)} />
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
return (
|
|
129
|
+
<ScrollView>
|
|
130
|
+
{posts.map(post => renderItem({ item: post }))}
|
|
131
|
+
</ScrollView>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Output
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
BRIDGE REVIEW
|
|
140
|
+
=============
|
|
141
|
+
File: src/screens/FeedScreen.tsx
|
|
142
|
+
Component Type: Screen
|
|
143
|
+
Issues Found: 4 Critical: 2 Warning: 1 Info: 1
|
|
144
|
+
|
|
145
|
+
FINDINGS
|
|
146
|
+
--------
|
|
147
|
+
[CRITICAL] Line 5 — AsyncStorage bridge call in useEffect without error handling
|
|
148
|
+
Problem : AsyncStorage.getItem crosses the JS-to-Native bridge on every mount.
|
|
149
|
+
If this fires during fast navigation or background app state, it can
|
|
150
|
+
stall the JS thread. More critically, missing .catch means storage
|
|
151
|
+
errors are silently dropped.
|
|
152
|
+
Fix : useEffect(() => {
|
|
153
|
+
AsyncStorage.getItem('cached_posts')
|
|
154
|
+
.then(data => { if (data) setPosts(JSON.parse(data)); })
|
|
155
|
+
.catch(e => console.error('Cache read failed', e));
|
|
156
|
+
fetchPosts().then(setPosts).catch(handleError);
|
|
157
|
+
}, []);
|
|
158
|
+
|
|
159
|
+
[CRITICAL] Line 16 — ScrollView with .map() instead of FlatList
|
|
160
|
+
Problem : ScrollView renders ALL posts at once. For a feed with 100+ posts,
|
|
161
|
+
this mounts every PostCard simultaneously, causing severe memory
|
|
162
|
+
pressure and slow initial render. I have seen this cause 5-second
|
|
163
|
+
screen loads on mid-range Android devices.
|
|
164
|
+
Fix : <FlatList
|
|
165
|
+
data={posts}
|
|
166
|
+
keyExtractor={item => item.id}
|
|
167
|
+
renderItem={renderItem}
|
|
168
|
+
removeClippedSubviews
|
|
169
|
+
initialNumToRender={10}
|
|
170
|
+
/>
|
|
171
|
+
|
|
172
|
+
[WARNING] Line 11 — renderItem not memoized
|
|
173
|
+
Problem : renderItem is recreated on every render, causing FlatList (once migrated)
|
|
174
|
+
to re-render every item on parent state changes.
|
|
175
|
+
Fix : const renderItem = useCallback(({ item }: { item: Post }) => (
|
|
176
|
+
<PostCard post={item} onLike={() => handleLike(item.id)} />
|
|
177
|
+
), [handleLike]);
|
|
178
|
+
|
|
179
|
+
[INFO] Lines 1–18 — Old Architecture patterns
|
|
180
|
+
Problem : This component is compatible with New Architecture but not optimized
|
|
181
|
+
for it. AsyncStorage should be replaced with MMKV (synchronous,
|
|
182
|
+
JSI-based) for cache reads.
|
|
183
|
+
Fix : import { MMKV } from 'react-native-mmkv';
|
|
184
|
+
const storage = new MMKV();
|
|
185
|
+
const cached = storage.getString('cached_posts'); // synchronous, no bridge
|
|
186
|
+
|
|
187
|
+
BRIDGE CROSSING REPORT
|
|
188
|
+
-----------------------
|
|
189
|
+
Synchronous bridge calls: 0
|
|
190
|
+
Bridge calls in render path: No
|
|
191
|
+
→ AsyncStorage is in useEffect, not render — correct placement.
|
|
192
|
+
|
|
193
|
+
RE-RENDER ANALYSIS
|
|
194
|
+
------------------
|
|
195
|
+
Missing memoization: Yes
|
|
196
|
+
→ renderItem function recreated every render (line 11).
|
|
197
|
+
Prop drilling detected: No
|
|
198
|
+
|
|
199
|
+
NEW ARCHITECTURE READINESS: Needs Work
|
|
200
|
+
→ AsyncStorage uses Old Architecture bridge. Replace with MMKV or Expo FileSystem.
|
|
201
|
+
|
|
202
|
+
VERDICT: NEEDS WORK
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Notes
|
|
208
|
+
|
|
209
|
+
- Provide the full component including imports for accurate architecture detection.
|
|
210
|
+
- For NativeModule files, include the JavaScript interface and native implementation together.
|
|
211
|
+
- BRIDGE focuses on runtime performance, not visual correctness.
|
|
212
|
+
- Tested with: Claude Sonnet 4.6.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# React Native Performance Optimizer Agent
|
|
2
|
+
|
|
3
|
+
> Paste a React Native component. Get a ranked list of re-render bottlenecks, FlatList issues, bridge overhead, and animation problems — with corrected TypeScript for each fix.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## What This Agent Does
|
|
8
|
+
|
|
9
|
+
Analyzes React Native TypeScript components for performance issues and returns findings ranked by impact:
|
|
10
|
+
|
|
11
|
+
- **Re-render prevention** — missing `useCallback`, `useMemo`, `React.memo`; inline functions and objects in JSX
|
|
12
|
+
- **FlatList / FlashList** — `keyExtractor`, `getItemLayout`, `windowSize`, `removeClippedSubviews`, `initialNumToRender`
|
|
13
|
+
- **Bridge overhead** — `NativeModules` calls in render paths, synchronous bridge calls (Old Architecture)
|
|
14
|
+
- **Animation thread** — animations running on JS thread instead of native thread (`useNativeDriver: true`)
|
|
15
|
+
- **Context re-renders** — large context consumers that re-render on unrelated context changes
|
|
16
|
+
|
|
17
|
+
Every finding includes: impact estimate (re-renders/interaction or FPS impact), root-cause explanation, and corrected TypeScript code.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Files
|
|
22
|
+
|
|
23
|
+
| File | Purpose |
|
|
24
|
+
|---|---|
|
|
25
|
+
| [`agent.md`](agent.md) | Input format, output format, full system prompt |
|
|
26
|
+
| [`example-input.md`](example-input.md) | FeedScreen with 4 intentional performance issues |
|
|
27
|
+
| [`example-output.md`](example-output.md) | Ranked performance audit with fixes |
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
RN_VERSION: 0.76
|
|
35
|
+
ARCH: new
|
|
36
|
+
FILE_PATH: src/screens/FeedScreen.tsx
|
|
37
|
+
CODE:
|
|
38
|
+
[paste your component]
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Set `ARCH: old` for Bridge architecture apps, `ARCH: new` for JSI/Fabric apps.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Output Preview
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
PERFORMANCE AUDIT
|
|
49
|
+
=================
|
|
50
|
+
Issues Found: 4 | High: 2 | Medium: 1 | Low: 1
|
|
51
|
+
|
|
52
|
+
[HIGH] renderItem recreated on every parent render
|
|
53
|
+
Impact: Every state change forces re-render of all 10–20 visible PostCards.
|
|
54
|
+
Fix : const renderItem = useCallback(({ item }) => <PostCard ... />, [cardStyle])
|
|
55
|
+
|
|
56
|
+
[HIGH] Inline style object — new reference every renderItem call
|
|
57
|
+
Fix : const cardStyle = useMemo(() => ({ backgroundColor: theme.colors.background }),
|
|
58
|
+
[theme.colors.background])
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Full example: [`example-output.md`](example-output.md)
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## When to Use
|
|
66
|
+
|
|
67
|
+
| Symptom | Use This Agent |
|
|
68
|
+
|---|---|
|
|
69
|
+
| List scrolling drops below 60 FPS | Yes |
|
|
70
|
+
| Screens feel sluggish to respond | Yes |
|
|
71
|
+
| React DevTools Profiler shows many re-renders | Yes |
|
|
72
|
+
| Bridge calls visible in Flipper Bridge Spy | Yes (Old Arch) |
|
|
73
|
+
| App is fast but want to validate before shipping | Yes |
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Related Agents
|
|
78
|
+
|
|
79
|
+
- `skills/react-native/performance.md` — quick skill module for inline checks
|
|
80
|
+
- `skills/react-native/bridge-audit.md` — bridge-specific Old Architecture audit
|
|
81
|
+
- `prompts/react-native/component-audit.md` — single-component quick audit prompt
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
# Agent 05 — React Native Performance Optimizer
|
|
2
|
+
|
|
3
|
+
**Platform:** React Native (TypeScript)
|
|
4
|
+
**Category:** Performance & Optimization
|
|
5
|
+
**Complexity:** Medium–High
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Analyzes React Native TypeScript components for performance issues including unnecessary re-renders, missing memoization, bridge call overhead, FlatList misconfiguration, and image/animation bottlenecks. Returns ranked findings with a measurable impact estimate and specific refactored code for each fix.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Input Format
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
RN_VERSION: <e.g. 0.76>
|
|
19
|
+
ARCH: <old | new>
|
|
20
|
+
FILE_PATH: <relative path, e.g. src/screens/FeedScreen.tsx>
|
|
21
|
+
CODE:
|
|
22
|
+
<paste the full component file or relevant section>
|
|
23
|
+
PROFILER_DATA: <optional: paste Flipper or React DevTools Profiler output>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Fields:**
|
|
27
|
+
|
|
28
|
+
| Field | Required | Description |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| `RN_VERSION` | Yes | Determines available APIs (New Arch, Fabric, etc.) |
|
|
31
|
+
| `ARCH` | Yes | `new` for New Architecture (JSI/Fabric), `old` for Bridge |
|
|
32
|
+
| `FILE_PATH` | Yes | Helps infer component role (screen vs. list item vs. modal) |
|
|
33
|
+
| `CODE` | Yes | Full component source |
|
|
34
|
+
| `PROFILER_DATA` | No | React DevTools or Flipper performance trace for priority ranking |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Output Format
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
PERFORMANCE AUDIT
|
|
42
|
+
=================
|
|
43
|
+
File: <file path>
|
|
44
|
+
Component: <ComponentName>
|
|
45
|
+
Architecture: <Old Bridge | New Architecture (JSI/Fabric)>
|
|
46
|
+
Issues Found: <count>
|
|
47
|
+
High Impact: <count> Medium Impact: <count> Low Impact: <count>
|
|
48
|
+
|
|
49
|
+
FINDINGS (ranked by impact)
|
|
50
|
+
---------------------------
|
|
51
|
+
[HIGH] <Issue title>
|
|
52
|
+
Impact : <Estimated frames dropped or re-renders per interaction>
|
|
53
|
+
Problem : <What is happening and why it is expensive>
|
|
54
|
+
Refactored :
|
|
55
|
+
```tsx
|
|
56
|
+
<corrected code snippet>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
[MEDIUM] <Issue title>
|
|
60
|
+
Impact : <Estimated impact>
|
|
61
|
+
Problem : <What is happening>
|
|
62
|
+
Refactored :
|
|
63
|
+
```tsx
|
|
64
|
+
<corrected code snippet>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
[LOW] <Issue title>
|
|
68
|
+
Impact : <Estimated impact>
|
|
69
|
+
Problem : <What is happening>
|
|
70
|
+
Refactored :
|
|
71
|
+
```tsx
|
|
72
|
+
<corrected code snippet>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
BRIDGE / JSI OVERHEAD
|
|
76
|
+
---------------------
|
|
77
|
+
Synchronous bridge calls detected: Yes / No
|
|
78
|
+
→ <Which calls and alternatives>
|
|
79
|
+
|
|
80
|
+
ANIMATION SAFETY
|
|
81
|
+
----------------
|
|
82
|
+
Animations running on JS thread: Yes / No
|
|
83
|
+
→ <Which animations should use `useNativeDriver: true`>
|
|
84
|
+
|
|
85
|
+
FLATLIST / FLASHLIST AUDIT
|
|
86
|
+
--------------------------
|
|
87
|
+
N/A | Issues found: <count>
|
|
88
|
+
→ <keyExtractor, getItemLayout, windowSize, removeClippedSubviews issues>
|
|
89
|
+
|
|
90
|
+
ESTIMATED IMPROVEMENT
|
|
91
|
+
---------------------
|
|
92
|
+
Before: ~<N> renders per interaction
|
|
93
|
+
After : ~<N> renders per interaction
|
|
94
|
+
Expected FPS gain: <estimate or "measure to confirm">
|
|
95
|
+
|
|
96
|
+
RECOMMENDED PROFILING STEPS
|
|
97
|
+
----------------------------
|
|
98
|
+
1. <Specific Flipper / React DevTools step to validate the fix>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## System Prompt
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
You are a senior React Native performance engineer. Your job is to analyze React Native TypeScript components for performance problems and produce structured, actionable findings with refactored code.
|
|
107
|
+
|
|
108
|
+
Checks to perform:
|
|
109
|
+
1. Unnecessary re-renders: Are callbacks and objects recreated on every render without `useCallback`/`useMemo`? Are context values causing tree-wide re-renders?
|
|
110
|
+
2. Component memoization: Should this component be wrapped in `React.memo`? Are its props referentially stable?
|
|
111
|
+
3. FlatList/FlashList: Is `keyExtractor` returning stable keys? Is `getItemLayout` missing (causes full layout for every item)? Is `removeClippedSubviews` set? Is `windowSize` tuned?
|
|
112
|
+
4. Animations: Are Animated values using `useNativeDriver: true` where possible? Are Reanimated worklets free of JS-thread calls?
|
|
113
|
+
5. Bridge overhead (Old Arch): Are there synchronous calls to native modules in render paths? Can they be replaced with JSI or batched?
|
|
114
|
+
6. Image loading: Are images sized to display dimensions? Is `FastImage` or Expo Image used for caching?
|
|
115
|
+
7. Inline functions and objects in JSX: `onPress={() => fn(item)}` in a list cell forces every cell to re-render when the parent re-renders.
|
|
116
|
+
8. `useEffect` dependencies: Are effects running more often than needed?
|
|
117
|
+
|
|
118
|
+
For each finding:
|
|
119
|
+
- Rank by impact: HIGH (causes jank / dropped frames), MEDIUM (causes extra renders visible in profiler), LOW (minor).
|
|
120
|
+
- Estimate the impact in concrete terms (re-render count, frame budget).
|
|
121
|
+
- Provide a corrected code snippet — not pseudocode.
|
|
122
|
+
- Note when a fix requires measuring before and after to confirm.
|
|
123
|
+
|
|
124
|
+
Output MUST follow the exact format specified.
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Example
|
|
130
|
+
|
|
131
|
+
### Input
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
RN_VERSION: 0.76
|
|
135
|
+
ARCH: new
|
|
136
|
+
FILE_PATH: src/screens/FeedScreen.tsx
|
|
137
|
+
CODE:
|
|
138
|
+
const FeedScreen = () => {
|
|
139
|
+
const [posts, setPosts] = useState<Post[]>([]);
|
|
140
|
+
const theme = useContext(ThemeContext);
|
|
141
|
+
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
fetchPosts().then(setPosts);
|
|
144
|
+
}, []);
|
|
145
|
+
|
|
146
|
+
const renderItem = ({ item }: { item: Post }) => (
|
|
147
|
+
<PostCard
|
|
148
|
+
post={item}
|
|
149
|
+
onLike={() => handleLike(item.id)}
|
|
150
|
+
style={{ backgroundColor: theme.colors.background }}
|
|
151
|
+
/>
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
return (
|
|
155
|
+
<FlatList
|
|
156
|
+
data={posts}
|
|
157
|
+
renderItem={renderItem}
|
|
158
|
+
keyExtractor={(item) => item.id}
|
|
159
|
+
/>
|
|
160
|
+
);
|
|
161
|
+
};
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Output
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
PERFORMANCE AUDIT
|
|
168
|
+
=================
|
|
169
|
+
File: src/screens/FeedScreen.tsx
|
|
170
|
+
Component: FeedScreen
|
|
171
|
+
Architecture: New Architecture (JSI/Fabric)
|
|
172
|
+
Issues Found: 4
|
|
173
|
+
High Impact: 2 Medium Impact: 1 Low Impact: 1
|
|
174
|
+
|
|
175
|
+
FINDINGS (ranked by impact)
|
|
176
|
+
---------------------------
|
|
177
|
+
[HIGH] renderItem recreated on every parent render
|
|
178
|
+
Impact : Every state change in FeedScreen (including unrelated state)
|
|
179
|
+
recreates renderItem, which forces React to re-render every
|
|
180
|
+
visible PostCard — typically 10–20 items on screen.
|
|
181
|
+
Problem : `renderItem` is an inline function defined in the component body.
|
|
182
|
+
FlatList uses referential equality to bail out of re-renders.
|
|
183
|
+
A new function reference on every render defeats this.
|
|
184
|
+
Refactored :
|
|
185
|
+
```tsx
|
|
186
|
+
const renderItem = useCallback(({ item }: { item: Post }) => (
|
|
187
|
+
<PostCard
|
|
188
|
+
post={item}
|
|
189
|
+
onLike={() => handleLike(item.id)}
|
|
190
|
+
style={cardStyle}
|
|
191
|
+
/>
|
|
192
|
+
), [cardStyle]); // cardStyle extracted below
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
[HIGH] Inline style object created on every renderItem call
|
|
196
|
+
Impact : `{ backgroundColor: theme.colors.background }` is a new object
|
|
197
|
+
reference each render, breaking `React.memo` on PostCard even
|
|
198
|
+
if PostCard is memoized.
|
|
199
|
+
Problem : Objects created in JSX are never referentially equal across renders.
|
|
200
|
+
Refactored :
|
|
201
|
+
```tsx
|
|
202
|
+
const cardStyle = useMemo(
|
|
203
|
+
() => ({ backgroundColor: theme.colors.background }),
|
|
204
|
+
[theme.colors.background]
|
|
205
|
+
);
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
[MEDIUM] onLike callback captures item.id as a closure per cell
|
|
209
|
+
Impact : Each PostCard gets a unique `onLike` function. If PostCard is
|
|
210
|
+
wrapped in React.memo, it still re-renders when the parent
|
|
211
|
+
renderItem is recreated (addressed by HIGH fix above), but the
|
|
212
|
+
inline `() => handleLike(item.id)` still creates a new reference
|
|
213
|
+
per render per item.
|
|
214
|
+
Problem : Pass `item.id` as a prop and let PostCard call a stable callback.
|
|
215
|
+
Refactored :
|
|
216
|
+
```tsx
|
|
217
|
+
// In FeedScreen:
|
|
218
|
+
const handleLike = useCallback((id: string) => {
|
|
219
|
+
// like logic
|
|
220
|
+
}, []);
|
|
221
|
+
|
|
222
|
+
// In PostCard: accept onLike(id: string) and call it with own props.id
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
[LOW] FlatList missing getItemLayout
|
|
226
|
+
Impact : Without `getItemLayout`, FlatList cannot pre-calculate item
|
|
227
|
+
positions, causing extra layout passes when scrolling to an index
|
|
228
|
+
or on initial mount.
|
|
229
|
+
Problem : If PostCard has a fixed height, provide `getItemLayout`.
|
|
230
|
+
Refactored :
|
|
231
|
+
```tsx
|
|
232
|
+
const ITEM_HEIGHT = 120; // measure your PostCard
|
|
233
|
+
<FlatList
|
|
234
|
+
...
|
|
235
|
+
getItemLayout={(_, index) => ({
|
|
236
|
+
length: ITEM_HEIGHT,
|
|
237
|
+
offset: ITEM_HEIGHT * index,
|
|
238
|
+
index,
|
|
239
|
+
})}
|
|
240
|
+
/>
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
BRIDGE / JSI OVERHEAD
|
|
244
|
+
---------------------
|
|
245
|
+
Synchronous bridge calls detected: No
|
|
246
|
+
→ No native module calls detected in the render path.
|
|
247
|
+
|
|
248
|
+
ANIMATION SAFETY
|
|
249
|
+
----------------
|
|
250
|
+
Animations running on JS thread: No
|
|
251
|
+
→ No Animated or Reanimated usage detected in this file.
|
|
252
|
+
|
|
253
|
+
FLATLIST / FLASHLIST AUDIT
|
|
254
|
+
--------------------------
|
|
255
|
+
Issues found: 2
|
|
256
|
+
→ `keyExtractor` returns `item.id` — correct and stable.
|
|
257
|
+
→ `getItemLayout` missing — see LOW finding above.
|
|
258
|
+
→ Consider migrating to FlashList (Shopify) for lists with 50+ items;
|
|
259
|
+
it virtualizes more aggressively and performs better on New Architecture.
|
|
260
|
+
|
|
261
|
+
ESTIMATED IMPROVEMENT
|
|
262
|
+
---------------------
|
|
263
|
+
Before: ~10–20 PostCard re-renders per FeedScreen state change
|
|
264
|
+
After : ~0 PostCard re-renders for unrelated FeedScreen state changes
|
|
265
|
+
Expected FPS gain: Measure with React DevTools Profiler; expect 60 FPS sustained
|
|
266
|
+
during scroll on mid-range devices.
|
|
267
|
+
|
|
268
|
+
RECOMMENDED PROFILING STEPS
|
|
269
|
+
----------------------------
|
|
270
|
+
1. Open React DevTools → Profiler → Record while scrolling the feed.
|
|
271
|
+
2. Look for "Why did this render?" on PostCard — confirm it stops showing
|
|
272
|
+
"props changed" after applying the useCallback/useMemo fixes.
|
|
273
|
+
3. Enable "Highlight updates" in React DevTools to visually confirm only
|
|
274
|
+
newly loaded posts cause a re-render, not all visible posts.
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Notes
|
|
280
|
+
|
|
281
|
+
- For Old Architecture, the agent additionally checks for synchronous `NativeModules` calls in render paths.
|
|
282
|
+
- If `PROFILER_DATA` is provided, findings are ranked by actual measured render time, not heuristic estimates.
|
|
283
|
+
- The agent does not have visibility into PostCard's internals — it cannot confirm whether `React.memo` is already applied there.
|
|
284
|
+
- Tested with: Claude Sonnet 4.6, GPT-4o.
|