accessibility
Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android…
React Native and Expo app patterns — Expo Router navigation, state separation (server/client/route/form), TanStack Query data fetching with Zod, performant lists, NativeWind/StyleSheet styling, native APIs, and secure storage. Use when building or editing React Native / Expo
$ npx -y skills add affaan-m/ECC --skill react-native-patterns --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/react-native-patternsContext preview
The summary Claude sees to decide when to auto-load this skill.
React Native and Expo app patterns — Expo Router navigation, state separation (server/client/route/form), TanStack Query data fetching with Zod, performant lists, NativeWind/StyleSheet styling, native APIs, and secure storage. Use when building or editing React Native / Expo
name: react-native-patterns description: React Native and Expo app patterns — Expo Router navigation, state separation (server/client/route/form), TanStack Query data fetching with Zod, performant lists, NativeWind/StyleSheet styling, native APIs, and secure storage. Use when building or editing React Native / Expo screens, components, navigation, or data layers. origin: ECC
Practical patterns for building production React Native apps with Expo. Covers navigation, state, data fetching, lists, styling, and native APIs. Pairs with the `rules/react-native/` ruleset: rules say *what* to enforce, this skill shows *how*.
Libraries named below (NativeWind, Zustand/Jotai, TanStack Query) are common, well-established options shown for illustration — the patterns matter more than the specific package, and any equivalent works. Zod is used for validation to stay consistent with ECC's existing `typescript/` rules.
These patterns assume the managed Expo workflow (Expo Router, EAS, `expo-*` modules) on the New Architecture (the default in recent Expo SDKs, mandatory from SDK 55+). They do NOT assume the browser DOM — React Native has no `<div>`, no URL bar, and no web data-fetching defaults.
Use this skill when:
Do NOT use the web/React-DOM patterns here — URL-as-state, `<div>`, and SWR-for-browser do not apply to React Native.
File-based routing under `app/`. Keep route files thin: they read and validate params, then delegate to a screen component that lives in `components/` or `features/`.
app/
_layout.tsx # root stack
(tabs)/
_layout.tsx # tab navigator
index.tsx # Home
user/[id].tsx # dynamic route
components/
features/
user/UserProfile.tsxDeep links and dynamic routes deliver untrusted strings. Validate them with Zod before use.
// app/user/[id].tsx
import { useLocalSearchParams, router } from 'expo-router'
import { z } from 'zod'
import { UserProfile } from '@/features/user/UserProfile'
const Params = z.object({ id: z.string().uuid() })
export default function UserRoute() {
const parsed = Params.safeParse(useLocalSearchParams())
if (!parsed.success) {
router.replace('/not-found')
return null
}
return <UserProfile userId={parsed.data.id} />
}Do not duplicate server data into a client store. Each concern has its own home.
| Concern | Common choices | |---------|------| | Server state (remote data) | a server-cache library (TanStack Query, SWR) | | Client/UI state | a lightweight store (Zustand, Jotai) or Context | | Route/navigation state | Expo Router params | | Form state | a form library (e.g. React Hook Form) + schema validation | | Secrets / tokens | `expo-secure-store` | | Non-secret persistence | `AsyncStorage` / MMKV |
Prefer local `useState` until state genuinely needs sharing.
Use a server-cache library (TanStack Query, SWR) instead of fetch-in-`useEffect`. Validate at the boundary and infer types from the schema. Handle loading, error, and empty states explicitly. (Example uses TanStack Query.)
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { z } from 'zod'
const User = z.object({ id: z.string(), email: z.string().email() })
type User = z.infer<typeof User>
export function useUser(id: string) {
return useQuery({
queryKey: ['user', id],
queryFn: async (): Promise<User> => User.parse(await api.getUser(id)),
})
}
export function useUpdateEmail(id: string) {
const qc = useQueryClient()
return useMutation({
mutationFn: (email: string) => api.updateEmail(id, email),
onSuccess: () => qc.invalidateQueries({ queryKey: ['user', id] }),
})
}import { FlatList } from 'react-native'
<FlatList
data={items}
keyExtractor={(item) => item.id}
renderItem={renderItem} // memoized
initialNumToRender={10}
windowSize={5}
/>Use `FlashList` (Shopify) for large or heterogeneous lists.
`StyleSheet.create()` is the framework-native option; utility-class libraries (e.g. NativeWind) are a common alternative. Choose one and stay consistent. Never build style objects inline in JSX on hot paths.
// NativeWind
<View className="p-4 rounded-2xl bg-white">
<Text className="text-base font-semibold">Hello</Text>
</View>
// StyleSheet
const styles = StyleSheet.create({ card: { padding: 16, borderRadius: 16, backgroundColor: '#fff' } })
<View style={styles.card}>...</View>Keep Expo SDK calls and subscriptions inside `use*` hooks, not in JSX. Always clean up.
import { useEffect, useState } from 'react'
import * as Location from 'expo-location'
type LocationState =
| { status: 'loading' }
| { status: 'denied' }
| { status: 'granted'; coords: Location.LocationObjectCoords }
export function useCurrentLocation() {
// Track status, not just coords — so the UI can tell "still loading" apart
// from "permission denied" and show an actionable message.
const [state, setState] = useState<LocationState>({ status: 'loading' })
useEffect(() => {
let active = true
;(async () => {Your agent can write code, but ECC gives it a coordinated engineering system and toolbox: it plans before it builds, verifies changes with tests, reviews its own work from a fresh context, remembers what matters, and turns repeated wins into reusable skills
Repo: affaan-m/ECC
Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android…
Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for…
Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks…
Design and optimize AI agent action spaces, tool definitions, and observation formatting for…
Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained…
Use after completing any non-trivial task. The agent self-rates its output on 5 axes —…