Capacitor React

capawesome-team/skills/skills/capacitor-react

作者 capawesome-teamc58aeb068d27MIT45 個星標收錄於 2026年10月9日更新於 2026年10月9日儲存庫3 天前更新

Guides the agent through Capacitor app development with React — project structure, hooks for native features, state management patterns, using Capacitor plugins in React components, and React-specific best practices. Do not use for Ionic Framework with React (use ionic-react), migrating or upgrading Capacitor apps or plugins, or non-React frameworks.

AI 產生的概覽

指導以 React 開發 Capacitor 行動應用,涵蓋專案結構、原生外掛 Hook、狀態管理與生命週期。

功能
提供以 React 建置 Capacitor 應用程式的逐步指引,包括專案分析、目錄結構,以及在元件與自訂 Hook 中呼叫 Capacitor 外掛的模式。內容涵蓋狀態管理整合、深層連結、Android 返回鍵處理、平台特定渲染與應用程式生命週期事件。也列出建置、同步與即時重載指令,以及常見錯誤的修正方式。
適用情境
適用於開發或維護使用 React 18 或更新版本的 Capacitor 6、7 或 8 應用程式,且需要存取原生裝置功能時。不適用於 Ionic Framework 搭配 React、Capacitor 移轉或升級,以及非 React 框架。
執行需求
需要 Capacitor 6/7/8 應用程式、React 18 或更新版本、Node.js 與 npm;iOS 需要 macOS 上的 Xcode,Android 需要 Android Studio。此技能不含指令碼,只有說明文件與兩份參考文件。

Capacitor React

Develop Capacitor apps with React — project structure, hooks, state management, and React-specific patterns for accessing native device features.

Prerequisites

  1. Capacitor 6, 7, or 8 app with React.
  2. Node.js and npm installed.
  3. React 18 or later.
  4. For iOS: Xcode installed.
  5. For Android: Android Studio installed.

Agent Behavior

  • Auto-detect before asking. Check the project for package.json dependencies (react, react-dom, @capacitor/core), platforms (android/, ios/), build tools (vite.config.ts, next.config.js, webpack.config.js), and TypeScript usage. Only ask the user when something cannot be detected.
  • Guide step-by-step. Walk the user through the process one step at a time. Never present multiple unrelated questions at once.
  • Adapt to the project. Detect the existing code style (functional vs. class components, TypeScript vs. JavaScript, CSS modules vs. styled-components) and generate code that matches.

Procedures

Step 1: Analyze the Project

Auto-detect the following by reading project files:

  1. Framework variant: Check if this is a plain React app (Vite/CRA), Next.js, or Remix by examining package.json dependencies and config files (vite.config.ts, next.config.js, remix.config.js).
  2. Capacitor version: Read @capacitor/core version from package.json.
  3. React version: Read react version from package.json.
  4. TypeScript: Check if tsconfig.json exists and if .tsx files are used.
  5. Platforms: Check which directories exist (android/, ios/).
  6. Capacitor config format: Check if the project uses capacitor.config.ts or capacitor.config.json.
  7. State management: Check package.json for redux, @reduxjs/toolkit, zustand, jotai, @tanstack/react-query, or similar.
  8. Router: Check package.json for react-router-dom, @tanstack/react-router, or similar.

Step 2: Project Structure

A standard Capacitor React project follows this structure:

project-root/├── android/                  # Android native project (generated by Capacitor)├── ios/                      # iOS native project (generated by Capacitor)├── public/├── src/│   ├── components/           # Reusable UI components│   ├── hooks/                # Custom React hooks (including native feature hooks)│   ├── pages/                # Page/route components│   ├── services/             # Service modules for Capacitor plugin calls│   ├── App.tsx               # Root component│   └── main.tsx              # Entry point├── capacitor.config.ts       # Capacitor configuration├── package.json├── tsconfig.json└── vite.config.ts            # Or other bundler config

If the project does not follow this structure, adapt all guidance to the project's actual directory layout. Do not restructure the project unless the user explicitly asks.

Step 3: Using Capacitor Plugins in React

Read references/plugin-usage-patterns.md for detailed patterns on how to use Capacitor plugins in React components and hooks.

Key principles:

  1. Import plugins directly — Capacitor plugins are imported as ES modules.
  2. Call plugin methods in event handlers or effects — never at the module top level.
  3. Use useEffect for listeners — register and clean up Capacitor event listeners inside useEffect.
  4. Check platform before calling — use Capacitor.isNativePlatform() or Capacitor.getPlatform() to guard platform-specific calls.

Step 4: Custom Hooks for Native Features

Read references/custom-hooks.md for reusable custom hook patterns that wrap Capacitor plugins.

Custom hooks encapsulate native feature access and provide a React-idiomatic API. When the user needs to access a native feature from multiple components, create a custom hook in src/hooks/ (or wherever the project keeps hooks).

Step 5: State Management with Native Data

When the project uses a state management library, integrate native data as follows:

  1. React Query / TanStack Query: Use query functions that call Capacitor plugins. This works well for data that is fetched from native APIs (e.g., device info, contacts, filesystem reads).
  2. Redux / Zustand / Jotai: Dispatch actions or update atoms from Capacitor plugin callbacks. Keep native API calls in action creators or service modules, not in reducers or stores.
  3. No state library: Use React context or custom hooks with useState/useReducer to share native data across components.

Do not recommend adding a state management library unless the user's requirements justify it.

Step 6: Navigation and Deep Links

If the project uses react-router-dom or another router:

  1. Deep links: Register a listener for appUrlOpen events from the @capacitor/app plugin inside a useEffect in the root component or a dedicated hook. Navigate programmatically using the router's useNavigate() hook.
typescript
import { useEffect } from 'react';import { useNavigate } from 'react-router-dom';import { App, URLOpenListenerEvent } from '@capacitor/app';
const useDeepLinks = () => {  const navigate = useNavigate();
  useEffect(() => {    const listener = App.addListener('appUrlOpen', (event: URLOpenListenerEvent) => {      const path = new URL(event.url).pathname;      navigate(path);    });
    return () => {      listener.then(handle => handle.remove());    };  }, [navigate]);};
  1. Back button handling (Android): Register a listener for the backButton event from the @capacitor/app plugin to handle Android hardware back button presses.
typescript
import { useEffect } from 'react';import { useNavigate, useLocation } from 'react-router-dom';import { App } from '@capacitor/app';
const useBackButton = () => {  const navigate = useNavigate();  const location = useLocation();
  useEffect(() => {    const listener = App.addListener('backButton', ({ canGoBack }) => {      if (canGoBack) {        navigate(-1);      } else {        App.exitApp();      }    });
    return () => {      listener.then(handle => handle.remove());    };  }, [navigate, location]);};

Step 7: Platform-Specific Rendering

Use Capacitor.getPlatform() or Capacitor.isNativePlatform() to conditionally render components or apply platform-specific behavior:

typescript
import { Capacitor } from '@capacitor/core';
const MyComponent: React.FC = () => {  const platform = Capacitor.getPlatform(); // 'ios' | 'android' | 'web'  const isNative = Capacitor.isNativePlatform();
  return (    <div>      {platform === 'ios' && <IOSSpecificComponent />}      {platform === 'android' && <AndroidSpecificComponent />}      {!isNative && <WebFallbackComponent />}    </div>  );};

For reusable platform checks, create a utility or hook:

typescript
import { Capacitor } from '@capacitor/core';
export const usePlatform = () => {  return {    platform: Capacitor.getPlatform(),    isNative: Capacitor.isNativePlatform(),    isIOS: Capacitor.getPlatform() === 'ios',    isAndroid: Capacitor.getPlatform() === 'android',    isWeb: Capacitor.getPlatform() === 'web',  };};

Step 8: Lifecycle and App State

Use the @capacitor/app plugin to respond to app lifecycle events in React:

typescript
import { useEffect } from 'react';import { App } from '@capacitor/app';
const useAppState = (onResume?: () => void, onPause?: () => void) => {  useEffect(() => {    const resumeListener = App.addListener('resume', () => {      onResume?.();    });
    const pauseListener = App.addListener('pause', () => {      onPause?.();    });
    return () => {      resumeListener.then(handle => handle.remove());      pauseListener.then(handle => handle.remove());    };  }, [onResume, onPause]);};

Use this to refresh data when the app returns to the foreground, pause media, or save state when the app is backgrounded.

Step 9: Build and Run

After implementing changes:

bash
npm run buildnpx cap syncnpx cap run androidnpx cap run ios

For development with live reload:

bash
npx cap run android --livereload --externalnpx cap run ios --livereload --external

The --external flag makes the dev server accessible from the device/emulator. The --livereload flag enables automatic reloads when source files change.

Error Handling

  • Plugin not found at runtime: Ensure npx cap sync was run after installing a plugin. Verify the plugin is listed in package.json dependencies.
  • Capacitor is not defined: The @capacitor/core package must be installed. Run npm install @capacitor/core.
  • Native method fails on web: Guard native-only calls with Capacitor.isNativePlatform(). Many plugins have web implementations, but some (e.g., @capacitor/camera with native UI) only work on iOS/Android.
  • Event listener memory leak: Always return a cleanup function from useEffect that calls remove() on the listener handle. Failing to do so causes duplicate listeners on re-renders.
  • Stale closure in event listener: If a Capacitor event listener references React state that changes over time, use a useRef to hold the latest value, or add the state variable to the useEffect dependency array and re-register the listener.
  • Live reload not connecting: Ensure the device and development machine are on the same network. Check that the --external flag is used with npx cap run. Verify no firewall is blocking the dev server port.
  • Build works on web but fails on native: Check for browser-only APIs (window.localStorage, navigator.geolocation) used without Capacitor alternatives. Use Capacitor plugins (@capacitor/preferences, @capacitor/geolocation) instead.
  • React strict mode double-mounting: In development, React 18 strict mode mounts components twice. This can cause duplicate Capacitor event listeners. Ensure cleanup functions properly remove listeners — the double-mount behavior validates that cleanup works correctly.

Related Skills

  • ionic-react — Ionic Framework-specific React patterns (IonReactRouter, lifecycle hooks, overlay hooks) for apps using @ionic/react.
  • capacitor-angular — Angular-specific patterns and best practices for Capacitor app development.
  • capacitor-app-upgrades — Upgrade a Capacitor app to a newer major version.
  • capacitor-plugins — Install, configure, and use Capacitor plugins from official and community sources.
  • capacitor-push-notifications — Set up push notifications with Firebase Cloud Messaging in a Capacitor app.

來源與署名

來源:capawesome-team/skills位於skills/capacitor-react提交c58aeb0

授權條款: MIT

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架