Marketplace code-patterns-practices
React Native coding patterns, best practices, and common solutions for mobile development. Use when implementing features or refactoring code.
install
source · Clone the upstream repo
git clone https://github.com/aiskillstore/marketplace
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/aiskillstore/marketplace "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/babakbar/code-patterns-practices" ~/.claude/skills/aiskillstore-marketplace-code-patterns-practices && rm -rf "$T"
manifest:
skills/babakbar/code-patterns-practices/SKILL.mdsource content
Code Patterns & Practices
Common patterns and best practices for React Native development.
When to Use
- Implementing new features
- Refactoring existing code
- Choosing architecture patterns
- Solving common problems
- Improving code quality
Component Patterns
Custom Hooks
// Extract reusable logic function useToggle(initial = false) { const [value, setValue] = useState(initial); const toggle = useCallback(() => setValue(v => !v), []); return [value, toggle] as const; } // Usage const [isOpen, toggleOpen] = useToggle();
Compound Components
// Create flexible component APIs interface TabsProps { children: React.ReactNode; defaultValue?: string; } function Tabs({ children, defaultValue }: TabsProps) { const [active, setActive] = useState(defaultValue); return ( <TabsContext.Provider value={{ active, setActive }}> {children} </TabsContext.Provider> ); } Tabs.List = TabsList; Tabs.Trigger = TabsTrigger; Tabs.Content = TabsContent; // Usage <Tabs defaultValue="home"> <Tabs.List> <Tabs.Trigger value="home">Home</Tabs.Trigger> <Tabs.Trigger value="profile">Profile</Tabs.Trigger> </Tabs.List> <Tabs.Content value="home">Home Content</Tabs.Content> <Tabs.Content value="profile">Profile Content</Tabs.Content> </Tabs>
Render Props
// Share component logic interface DataLoaderProps<T> { loadData: () => Promise<T>; children: (data: T | null, loading: boolean, error: Error | null) => React.ReactNode; } function DataLoader<T>({ loadData, children }: DataLoaderProps<T>) { const [data, setData] = useState<T | null>(null); const [loading, setLoading] = useState(true); const [error, setError] = useState<Error | null>(null); useEffect(() => { loadData() .then(setData) .catch(setError) .finally(() => setLoading(false)); }, [loadData]); return <>{children(data, loading, error)}</>; } // Usage <DataLoader loadData={fetchUser}> {(user, loading, error) => { if (loading) return <Loading />; if (error) return <Error error={error} />; return <UserProfile user={user} />; }} </DataLoader>
State Management Patterns
Local State
// Keep it simple when possible function Counter() { const [count, setCount] = useState(0); return <Button onPress={() => setCount(c => c + 1)}>Count: {count}</Button>; }
Shared State (Context)
// For cross-cutting concerns const ThemeContext = createContext<ThemeContextValue>(null!); export function ThemeProvider({ children }: { children: React.ReactNode }) { const [theme, setTheme] = useState<'light' | 'dark'>('light'); return ( <ThemeContext.Provider value={{ theme, setTheme }}> {children} </ThemeContext.Provider> ); } export function useTheme() { const context = useContext(ThemeContext); if (!context) throw new Error('useTheme must be used within ThemeProvider'); return context; }
Global State (Zustand)
// For app-wide state import { create } from 'zustand'; interface UserState { user: User | null; setUser: (user: User) => void; logout: () => void; } export const useUserStore = create<UserState>((set) => ({ user: null, setUser: (user) => set({ user }), logout: () => set({ user: null }), }));
Data Fetching Patterns
With Async/Await
function useUserData(userId: string) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { let cancelled = false; async function fetchData() { try { const response = await fetch(`/api/users/${userId}`); const result = await response.json(); if (!cancelled) { setData(result); } } catch (err) { if (!cancelled) { setError(err); } } finally { if (!cancelled) { setLoading(false); } } } fetchData(); return () => { cancelled = true; }; }, [userId]); return { data, loading, error }; }
Performance Patterns
Memoization
// Expensive calculations const expensiveValue = useMemo(() => { return calculateExpensiveValue(data); }, [data]); // Stable callbacks const handlePress = useCallback(() => { doSomething(value); }, [value]); // Component memoization const MemoizedChild = memo(function Child({ data }: ChildProps) { return <View>{data}</View>; });
Lazy Loading
import { lazy, Suspense } from 'react'; const HeavyComponent = lazy(() => import('./HeavyComponent')); function App() { return ( <Suspense fallback={<Loading />}> <HeavyComponent /> </Suspense> ); }
Error Handling Patterns
Error Boundaries
class ErrorBoundary extends React.Component< { children: React.ReactNode }, { hasError: boolean; error: Error | null } > { state = { hasError: false, error: null }; static getDerivedStateFromError(error: Error) { return { hasError: true, error }; } componentDidCatch(error: Error, info: React.ErrorInfo) { console.error('Error caught:', error, info); } render() { if (this.state.hasError) { return <ErrorScreen error={this.state.error} />; } return this.props.children; } }
Try-Catch Pattern
async function saveData() { try { await api.save(data); showSuccess('Saved!'); } catch (error) { if (error instanceof NetworkError) { showError('Network error. Check connection.'); } else if (error instanceof ValidationError) { showError(error.message); } else { showError('Something went wrong.'); } } }
Mobile-Specific Patterns
Safe Area Handling
import { useSafeAreaInsets } from 'react-native-safe-area-context'; function Screen() { const insets = useSafeAreaInsets(); return ( <View style={{ paddingTop: insets.top, paddingBottom: insets.bottom }}> {/* Content */} </View> ); }
Keyboard Avoiding
import { KeyboardAvoidingView, Platform } from 'react-native'; <KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : 'height'} style={{ flex: 1 }} > {/* Input form */} </KeyboardAvoidingView>
Best Practices
- Keep Components Small: Single responsibility, easy to test
- Extract Custom Hooks: Reuse logic across components
- Use TypeScript: Catch errors early
- Handle Loading & Error States: Better user experience
- Clean Up Side Effects: Prevent memory leaks
- Optimize Wisely: Profile before optimizing
- Test Behavior: Focus on user interactions
Anti-Patterns to Avoid
- ❌ Massive components (>300 lines)
- ❌ Prop drilling (use context/store instead)
- ❌ Missing cleanup in useEffect
- ❌ Inline function definitions in render
- ❌ Mutating state directly
- ❌ Over-optimization without measuring