mcpField
R
react-native

react-native

github.com/gentleman-programmingDevelopment661262 installsUpdated 32w ago
Repository

About react-native

A development skill for building React Native apps, aimed at developers working with Expo, navigation, styling, or native platform code. It provides implementation patterns, examples, and quick references for common mobile app tasks.

Key features

  1. 01Typed functional component patterns
  2. 02Expo Router navigation examples
  3. 03iOS and Android-specific code guidance
  4. 04NativeWind styling examples
  5. 05Safe area and keyboard handling

Use cases

  1. 01Structuring a React Native application
  2. 02Implementing app navigation with Expo Router
  3. 03Adapting layouts for iOS and Android
  4. 04Building screens with NativeWind styling

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/gentleman-programming/gentleman-skills --skill react-native

After installing, type/react-nativein Claude Code to confirm it loaded.

Details

From the project README

When to Use

Load this skill when:

  • Building mobile applications with React Native
  • Working with Expo managed or bare workflow
  • Implementing navigation with React Navigation
  • Styling with NativeWind (Tailwind for RN)
  • Handling platform-specific code (iOS/Android)
  • Managing native modules and linking

Critical Patterns

Pattern 1: Project Structure
src/
├── app/                    # Expo Router screens (if using)
│   ├── (tabs)/            # Tab navigator group
│   ├── (auth)/            # Auth flow group
│   └── _layout.tsx        # Root layout
├── components/
│   ├── ui/                # Reusable UI components
│   └── features/          # Feature-specific components
├── hooks/                 # Custom hooks
├── services/              # API and external services
├── stores/                # State management (Zustand)
├── utils/                 # Utility functions
├── constants/             # App constants, themes
└── types/                 # TypeScript types
Pattern 2: Functional Components with TypeScript

Always use functional components with proper typing:

import { View, Text, Pressable } from 'react-native';
import type { ViewStyle, TextStyle } from 'react-native';

interface ButtonProps {
  title: string;
  onPress: () => void;
  variant?: 'primary' | 'secondary';
  disabled?: boolean;
}

export function Button({ 
  title, 
  onPress, 
  variant = 'primary',
  disabled = false 
}: ButtonProps) {
  return (
    <Pressable
      onPress={onPress}
      disabled={disabled}
      style={({ pressed }) => [
        styles.button,
        variant === 'secondary' && styles.buttonSecondary,
        pressed && styles.buttonPressed,
        disabled && styles.buttonDisabled,
      ]}
    >
      <Text style={styles.buttonText}>{title}</Text>
    </Pressable>
  );
}
Pattern 3: Platform-Specific Code

Use Platform module or file extensions for platform-specific code:

import { Platform, StyleSheet } from 'react-native';

// Using Platform.select
const styles = StyleSheet.create({
  container: {
    paddingTop: Platform.select({
      ios: 44,
      android: 0,
    }),
    ...Platform.select({
      ios: {
        shadowColor: '#000',
        shadowOffset: { width: 0, height: 2 },
        shadowOpacity: 0.1,
        shadowRadius: 4,
      },
      android: {
        elevation: 4,
      },
    }),
  },
});

// Or use file extensions:
// Component.ios.tsx
// Component.android.tsx

Code Examples

Example 1: Expo Router Navigation Setup
// app/_layout.tsx
import { Stack } from 'expo-router';
import { StatusBar } from 'expo-status-bar';

export default function RootLayout() {
  return (
    <>
      <StatusBar style="auto" />
      <Stack
        screenOptions={{
          headerShown: false,
          animation: 'slide_from_right',
        }}
      >
        <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
        <Stack.Screen 
          name="modal" 
          options={{ 
            presentation: 'modal',
            animation: 'slide_from_bottom',
          }} 
        />
      </Stack>
    </>
  );
}
Example 2: Custom Hook with React Query
// hooks/useUser.ts
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { userService } from '@/services/user';
import type { User, UpdateUserInput } from '@/types';

export function useUser(userId: string) {
  return useQuery({
    queryKey: ['user', userId],
    queryFn: () => userService.getById(userId),
    staleTime: 5 * 60 * 1000, // 5 minutes
  });
}

export function useUpdateUser() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: (data: UpdateUserInput) => userService.update(data),
    onSuccess: (_, variables) => {
      queryClient.invalidateQueries({ queryKey: ['user', variables.id] });
    },
  });
}
Example 3: NativeWind Styling
// With NativeWind (Tailwind for React Native)
import { View, Text, Pressable } from 'react-native';
import { styled } from 'nativewind';

const StyledPressable = styled(Pressable);
const StyledView = styled(View);
const StyledText = styled(Text);

export function Card({ title, description, onPress }: CardProps) {
  return (
    <StyledPressable
      className="bg-white dark:bg-gray-800 rounded-2xl p-4 shadow-md active:scale-95"
      onPress={onPress}
    >
      <StyledView className="flex-row items-center gap-3">
        <StyledView className="w-12 h-12 bg-blue-100 dark:bg-blue-900 rounded-full items-center justify-center">
          <StyledText className="text-blue-600 dark:text-blue-300 text-xl">
            📱
          </StyledText>
        </StyledView>
        <StyledView className="flex-1">
          <StyledText className="text-lg font-semibold text-gray-900 dark:text-white">
            {title}
          </StyledText>
          <StyledText className="text-sm text-gray-500 dark:text-gray-400">
            {description}
          </StyledText>
        </StyledView>
      </StyledView>
    </StyledPressable>
  );
}
Example 4: Safe Area and Keyboard Handling
import { KeyboardAvoidingView, Platform } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';

export function ScreenWrapper({ children }: { children: React.ReactNode }) {
  return (
    <SafeAreaView style={{ flex: 1 }} edges={['top', 'left', 'right']}>
      <KeyboardAvoidingView
        style={{ flex: 1 }}
        behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
        keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : 20}
      >
        {children}
      </KeyboardAvoidingView>
    </SafeAreaView>
  );
}
Example 5: Zustand Store with Persistence
// stores/authStore.ts
import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
import AsyncStorage from '@react-native-async-storage/async-storage';

interface AuthState {
  token: string | null;
  user: User | null;
  isAuthenticated: boolean;
  login: (token: string, user: User) => void;
  logout: () => void;
}

export const useAuthStore = create<AuthState>()(
  persist(
    (set) => ({
      token: null,
      user: null,
      isAuthenticated: false,
      login: (token, user) => set({ token, user, isAuthenticated: true }),
      logout: () => set({ token: null, user: null, isAuthenticated: false }),
    }),
    {
      name: 'auth-storage',
      storage: createJSONStorage(() => AsyncStorage),
    }
  )
);

Anti-Patterns

Don't: Inline Styles Everywhere
// ❌ Bad - inline styles are hard to maintain and don't memoize
export function BadComponent() {
  return (
    <View style={{ flex: 1, padding: 16, backgroundColor: '#fff' }}>
      <Text style={{ fontSize: 18, fontWeight: 'bold', color: '#333' }}>
        Title
      </Text>
    </View>
  );
}

// ✅ Good - use StyleSheet or NativeWind
const styles = StyleSheet.create({
  container: { flex: 1, padding: 16, backgroundColor: '#fff' },
  title: { fontSize: 18, fontWeight: 'bold', color: '#333' },
});

export function GoodComponent() {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Title</Text>
    </View>
  );
}
Don't: Use TouchableOpacity for Everything
// ❌ Bad - TouchableOpacity is legacy
import { TouchableOpacity } from 'react-native';

// ✅ Good - Use Pressable with feedback
import { Pressable } from 'react-native';

<Pressable
  onPress={onPress}
  style={({ pressed }) => [
    styles.button,
    pressed && { opacity: 0.7 }
  ]}
>
  {({ pressed }) => (
    <Text style={pressed ? styles.textPressed : styles.text}>
      Press Me
    </Text>
  )}
</Pressable>
Don't: Forget to Handle Loading and Error States
// ❌ Bad - no loading/error handling
export function UserProfile({ userId }: { userId: string }) {
  const { data } = useUser(userId);
  return <Text>{data.name}</Text>; // Will crash if data is undefined
}

// ✅ Good - handle all states
export function UserProfile({ userId }: { userId: string }) {
  const { data, isLoading, error } = useUser(userId);

  if (isLoading) return <LoadingSpinner />;
  if (error) return <ErrorMessage error={error} />;
  if (!data) return null;

  return <Text>{data.name}</Text>;
}

Quick Reference

TaskPattern
Create new Expo projectnpx create-expo-app@latest --template tabs
Add NativeWindnpx expo install nativewind tailwindcss
Platform checkPlatform.OS === 'ios'
Safe insetsuseSafeAreaInsets() from react-native-safe-area-context
Navigationrouter.push('/screen') with Expo Router
Deep linkingConfigure in app.json under expo.scheme
Environment varsUse expo-constants or react-native-dotenv
Icons@expo/vector-icons (included in Expo)
Animationsreact-native-reanimated for 60fps animations
Gesturesreact-native-gesture-handler

Resources

Comments

Markdown supported