React集成 #
一、项目搭建 #
1.1 使用 Vite 创建项目 #
bash
# 创建 React + TypeScript 项目
npm create vite@latest my-electron-react -- --template react-ts
# 进入项目目录
cd my-electron-react
# 安装 Electron
npm install electron --save-dev
npm install electron-builder --save-dev
# 安装开发工具
npm install vite-plugin-electron --save-dev
npm install electron-reload --save-dev
1.2 项目结构 #
text
my-electron-react/
├── electron/
│ ├── main.ts # 主进程
│ ├── preload.ts # 预加载脚本
│ └── utils/ # 工具函数
├── src/
│ ├── App.tsx # React 根组件
│ ├── main.tsx # 入口文件
│ ├── components/ # 组件目录
│ ├── hooks/ # 自定义 Hooks
│ ├── stores/ # 状态管理
│ ├── utils/ # 工具函数
│ └── types/ # 类型定义
├── public/ # 静态资源
├── vite.config.ts # Vite 配置
├── electron-builder.yml # 打包配置
└── package.json
1.3 Vite 配置 #
typescript
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import electron from 'vite-plugin-electron';
import path from 'path';
export default defineConfig({
plugins: [
react(),
electron([
{
entry: 'electron/main.ts',
onstart(options) {
options.startup();
},
vite: {
build: {
outDir: 'dist-electron',
rollupOptions: {
external: ['electron']
}
}
}
},
{
entry: 'electron/preload.ts',
onstart(options) {
options.reload();
},
vite: {
build: {
outDir: 'dist-electron'
}
}
}
])
],
resolve: {
alias: {
'@': path.resolve(__dirname, './src')
}
},
base: './',
build: {
outDir: 'dist'
}
});
二、主进程配置 #
2.1 主进程入口 #
typescript
// electron/main.ts
import { app, BrowserWindow, ipcMain } from 'electron';
import path from 'path';
const isDev = !app.isPackaged;
let mainWindow: BrowserWindow | null = null;
function createWindow() {
mainWindow = new BrowserWindow({
width: 1200,
height: 800,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: false,
contextIsolation: true
}
});
if (isDev) {
mainWindow.loadURL('http://localhost:5173');
mainWindow.webContents.openDevTools();
} else {
mainWindow.loadFile(path.join(__dirname, '../dist/index.html'));
}
mainWindow.on('closed', () => {
mainWindow = null;
});
}
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (mainWindow === null) {
createWindow();
}
});
2.2 预加载脚本 #
typescript
// electron/preload.ts
import { contextBridge, ipcRenderer } from 'electron';
contextBridge.exposeInMainWorld('electronAPI', {
getAppInfo: () => ipcRenderer.invoke('get-app-info'),
openFile: () => ipcRenderer.invoke('open-file'),
saveFile: (content: string) => ipcRenderer.invoke('save-file', content)
});
三、React 集成 #
3.1 类型定义 #
typescript
// src/types/electron.d.ts
export interface ElectronAPI {
getAppInfo: () => Promise<{ version: string; platform: string }>;
openFile: () => Promise<string | null>;
saveFile: (content: string) => Promise<boolean>;
}
declare global {
interface Window {
electronAPI: ElectronAPI;
}
}
3.2 自定义 Hook #
typescript
// src/hooks/useElectron.ts
import { useState, useEffect } from 'react';
export function useAppInfo() {
const [info, setInfo] = useState<{ version: string; platform: string } | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
window.electronAPI.getAppInfo()
.then(setInfo)
.finally(() => setLoading(false));
}, []);
return { info, loading };
}
export function useFileOperations() {
const openFile = async () => {
return await window.electronAPI.openFile();
};
const saveFile = async (content: string) => {
return await window.electronAPI.saveFile(content);
};
return { openFile, saveFile };
}
3.3 React 组件示例 #
tsx
// src/App.tsx
import { useState } from 'react';
import { useAppInfo, useFileOperations } from './hooks/useElectron';
function App() {
const { info, loading } = useAppInfo();
const { openFile, saveFile } = useFileOperations();
const [content, setContent] = useState('');
const handleOpen = async () => {
const fileContent = await openFile();
if (fileContent) {
setContent(fileContent);
}
};
const handleSave = async () => {
await saveFile(content);
};
if (loading) {
return <div>Loading...</div>;
}
return (
<div className="app">
<header>
<h1>Electron + React App</h1>
<p>Version: {info?.version}</p>
<p>Platform: {info?.platform}</p>
</header>
<main>
<div className="toolbar">
<button onClick={handleOpen}>Open</button>
<button onClick={handleSave}>Save</button>
</div>
<textarea
value={content}
onChange={(e) => setContent(e.target.value)}
placeholder="Enter text here..."
/>
</main>
</div>
);
}
export default App;
四、状态管理 #
4.1 使用 Zustand #
bash
npm install zustand
typescript
// src/stores/appStore.ts
import { create } from 'zustand';
interface AppState {
theme: 'light' | 'dark';
sidebarOpen: boolean;
setTheme: (theme: 'light' | 'dark') => void;
toggleSidebar: () => void;
}
export const useAppStore = create<AppState>((set) => ({
theme: 'light',
sidebarOpen: true,
setTheme: (theme) => set({ theme }),
toggleSidebar: () => set((state) => ({ sidebarOpen: !state.sidebarOpen }))
}));
4.2 使用组件 #
tsx
// src/components/ThemeToggle.tsx
import { useAppStore } from '../stores/appStore';
export function ThemeToggle() {
const { theme, setTheme } = useAppStore();
return (
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Current theme: {theme}
</button>
);
}
五、路由配置 #
5.1 安装 React Router #
bash
npm install react-router-dom
5.2 路由配置 #
tsx
// src/router.tsx
import { createBrowserRouter } from 'react-router-dom';
import App from './App';
import Home from './pages/Home';
import Settings from './pages/Settings';
import About from './pages/About';
export const router = createBrowserRouter([
{
path: '/',
element: <App />,
children: [
{ index: true, element: <Home /> },
{ path: 'settings', element: <Settings /> },
{ path: 'about', element: <About /> }
]
}
]);
tsx
// src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { RouterProvider } from 'react-router-dom';
import { router } from './router';
import './index.css';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>
);
六、打包配置 #
6.1 package.json #
json
{
"name": "my-electron-react",
"version": "1.0.0",
"main": "dist-electron/main.js",
"scripts": {
"dev": "vite",
"build": "tsc && vite build && electron-builder",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.20.0",
"zustand": "^4.4.7"
},
"devDependencies": {
"@types/react": "^18.2.43",
"@types/react-dom": "^18.2.17",
"@vitejs/plugin-react": "^4.2.1",
"electron": "^28.0.0",
"electron-builder": "^24.9.1",
"typescript": "^5.3.3",
"vite": "^5.0.8",
"vite-plugin-electron": "^0.28.0"
}
}
6.2 electron-builder.yml #
yaml
appId: com.example.myapp
productName: My Electron React App
directories:
output: release
files:
- dist/**/*
- dist-electron/**/*
mac:
icon: build/icon.icns
win:
icon: build/icon.ico
linux:
icon: build/icon.png
七、最佳实践 #
7.1 开发建议 #
markdown
- [ ] 使用 TypeScript 类型安全
- [ ] 使用 Vite 加速开发
- [ ] 组件化开发
- [ ] 状态管理统一
- [ ] IPC 通信封装
7.2 性能优化 #
typescript
// 使用 React.lazy 懒加载
const Settings = React.lazy(() => import('./pages/Settings'));
// 使用 Suspense
<Suspense fallback={<div>Loading...</div>}>
<Settings />
</Suspense>
八、总结 #
8.1 核心要点 #
| 要点 | 说明 |
|---|---|
| Vite | 推荐的构建工具 |
| TypeScript | 类型安全 |
| IPC 封装 | 自定义 Hook 封装 |
| 状态管理 | Zustand/Redux |
8.2 下一步 #
现在你已经掌握了 React 集成,接下来让我们学习 Vue集成,深入了解 Electron 与 Vue 的集成开发!
最后更新:2026-03-28