jpskill.com
🛠️ 開発・MCP コミュニティ

code-patterns-practices

React Native coding patterns, best practices, and common solutions for mobile development. Use when implementing features or refactoring code.

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o code-patterns-practices.zip https://jpskill.com/download/17418.zip && unzip -o code-patterns-practices.zip && rm code-patterns-practices.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/17418.zip -OutFile "$d\code-patterns-practices.zip"; Expand-Archive "$d\code-patterns-practices.zip" -DestinationPath $d -Force; ri "$d\code-patterns-practices.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して code-patterns-practices.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → code-patterns-practices フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

コードパターンとプラクティス

React Native 開発における一般的なパターンとベストプラクティスです。

いつ使うか

  • 新機能の実装
  • 既存のコードのリファクタリング
  • アーキテクチャパターンの選択
  • 一般的な問題の解決
  • コード品質の向上

コンポーネントパターン

カスタムフック

// 再利用可能なロジックを抽出します
function useToggle(initial = false) {
  const [value, setValue] = useState(initial);
  const toggle = useCallback(() => setValue(v => !v), []);
  return [value, toggle] as const;
}

// 使用例
const [isOpen, toggleOpen] = useToggle();

複合コンポーネント

// 柔軟なコンポーネント API を作成します
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;

// 使用例
<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

// コンポーネントロジックを共有します
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)}</>;
}

// 使用例
<DataLoader loadData={fetchUser}>
  {(user, loading, error) => {
    if (loading) return <Loading />;
    if (error) return <Error error={error} />;
    return <UserProfile user={user} />;
  }}
</DataLoader>

状態管理パターン

ローカルステート

// 可能な限りシンプルに保ちます
function Counter() {
  const [count, setCount] = useState(0);
  return <Button onPress={() => setCount(c => c + 1)}>Count: {count}</Button>;
}

共有ステート (Context)

// 共通の関心事のために
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;
}

グローバルステート (Zustand)

// アプリ全体のステートのために
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 }),
}));

データ取得パターン

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 };
}

パフォーマンスパターン

メモ化

// コストのかかる計算
const expensiveValue = useMemo(() => {
  return calculateExpensiveValue(data);
}, [data]);

// 安定したコールバック
const handlePress = useCallback(() => {
  doSomething(value);
}, [value]);

// コンポーネントのメモ化
const MemoizedChild = memo(function Child({ data }: ChildProps) {
  return <View>{data}</View>;
});

遅延ロード

import { lazy, Suspense } from 'react';

const HeavyComponent = lazy(() => import('./HeavyComponent'));

function App() {
  return (
    <Suspense fallback={<Loading />}>
      <HeavyComponent />
    </Suspense>
  );
}

エラー処理パターン

エラー境界

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 パターン

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.');
    }
  }
}

モバイル固有のパターン

セーフエリアの処理

import { useSafeAreaInsets } from 'react-native-safe-area-context';

function Screen() {
  const insets = useSafeAreaInsets
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

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

  1. Keep Components Small: Single responsibility, easy to test
  2. Extract Custom Hooks: Reuse logic across components
  3. Use TypeScript: Catch errors early
  4. Handle Loading & Error States: Better user experience
  5. Clean Up Side Effects: Prevent memory leaks
  6. Optimize Wisely: Profile before optimizing
  7. 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

Resources