<< All versions
Skill v1.0.0
currentAutomated scan100/100alinaqi/claude-bootstrap/react-native
──Details
PublishedOctober 19, 2026 at 08:26 PM
Content Hashsha256:a42eb3117cc73a69...
Git SHAa273e93ce890
──Files
Files (1 file, 5.7 KB)
SKILL.md5.7 KBactive
SKILL.md · 250 lines · 5.7 KB
version: "1.0.0" name: react-native description: React Native mobile patterns, platform-specific code when-to-use: When working on React Native mobile app code user-invocable: false paths: ["/*.tsx", "/*.jsx", "ios/", "android/", "app.json"] effort: medium
React Native Skill
Project Structure
project/├── src/│ ├── core/ # Pure business logic (no React)│ │ ├── types.ts│ │ └── services/│ ├── components/ # Reusable UI components│ │ ├── Button/│ │ │ ├── Button.tsx│ │ │ ├── Button.test.tsx│ │ │ └── index.ts│ │ └── index.ts # Barrel export│ ├── screens/ # Screen components│ │ ├── Home/│ │ │ ├── HomeScreen.tsx│ │ │ ├── useHome.ts # Screen-specific hook│ │ │ └── index.ts│ │ └── index.ts│ ├── navigation/ # Navigation configuration│ ├── hooks/ # Shared custom hooks│ ├── store/ # State management│ └── utils/ # Utilities├── __tests__/├── android/├── ios/└── CLAUDE.md
Component Patterns
Functional Components Only
typescript
// Good - simple, testableinterface ButtonProps {label: string;onPress: () => void;disabled?: boolean;}export function Button({ label, onPress, disabled = false }: ButtonProps): JSX.Element {return (<Pressable onPress={onPress} disabled={disabled}><Text>{label}</Text></Pressable>);}
Extract Logic to Hooks
typescript
// useHome.ts - all logic hereexport function useHome() {const [items, setItems] = useState<Item[]>([]);const [loading, setLoading] = useState(false);const refresh = useCallback(async () => {setLoading(true);const data = await fetchItems();setItems(data);setLoading(false);}, []);return { items, loading, refresh };}// HomeScreen.tsx - pure presentationexport function HomeScreen(): JSX.Element {const { items, loading, refresh } = useHome();return (<ItemList items={items} loading={loading} onRefresh={refresh} />);}
Props Interface Always Explicit
typescript
// Always define props interface, even if simpleinterface ItemCardProps {item: Item;onPress: (id: string) => void;}export function ItemCard({ item, onPress }: ItemCardProps): JSX.Element {...}
State Management
Local State First
typescript
// Start with useState, escalate only when neededconst [value, setValue] = useState('');
Zustand for Global State (if needed)
typescript
// store/useAppStore.tsimport { create } from 'zustand';interface AppState {user: User | null;setUser: (user: User | null) => void;}export const useAppStore = create<AppState>((set) => ({user: null,setUser: (user) => set({ user }),}));
React Query for Server State
typescript
// hooks/useItems.tsimport { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';export function useItems() {return useQuery({queryKey: ['items'],queryFn: fetchItems,});}export function useCreateItem() {const queryClient = useQueryClient();return useMutation({mutationFn: createItem,onSuccess: () => {queryClient.invalidateQueries({ queryKey: ['items'] });},});}
Testing
Component Testing with React Native Testing Library
typescript
import { render, fireEvent } from '@testing-library/react-native';import { Button } from './Button';describe('Button', () => {it('calls onPress when pressed', () => {const onPress = jest.fn();const { getByText } = render(<Button label="Click me" onPress={onPress} />);fireEvent.press(getByText('Click me'));expect(onPress).toHaveBeenCalledTimes(1);});it('does not call onPress when disabled', () => {const onPress = jest.fn();const { getByText } = render(<Button label="Click me" onPress={onPress} disabled />);fireEvent.press(getByText('Click me'));expect(onPress).not.toHaveBeenCalled();});});
Hook Testing
typescript
import { renderHook, act } from '@testing-library/react-hooks';import { useCounter } from './useCounter';describe('useCounter', () => {it('increments counter', () => {const { result } = renderHook(() => useCounter());act(() => {result.current.increment();});expect(result.current.count).toBe(1);});});
Platform-Specific Code
Use Platform.select Sparingly
typescript
import { Platform } from 'react-native';const styles = StyleSheet.create({shadow: Platform.select({ios: {shadowColor: '#000',shadowOffset: { width: 0, height: 2 },shadowOpacity: 0.1,},android: {elevation: 2,},}),});
Separate Files for Complex Differences
Component/├── Component.tsx # Shared logic├── Component.ios.tsx # iOS-specific├── Component.android.tsx # Android-specific└── index.ts
React Native Anti-Patterns
- ❌ Inline styles - use StyleSheet.create
- ❌ Logic in render - extract to hooks
- ❌ Deep component nesting - flatten hierarchy
- ❌ Anonymous functions in props - use useCallback
- ❌ Index as key in lists - use stable IDs
- ❌ Direct state mutation - always use setter
- ❌ Mixing business logic with UI - keep core/ pure
- ❌ Ignoring TypeScript errors - fix them
- ❌ Large components - split into smaller pieces