求助:React+SQLite无后端构建CRUD应用及Electron离线应用实现方案
React + Electron 集成 SQLite 离线应用实现方案
为什么用Express打包后失效?
Electron分为主进程和渲染进程,用Express搭HTTP服务属于冗余设计——既增加复杂度,打包后还会因路径变更、服务启动逻辑冲突导致无法运行。直接在Electron主进程操作SQLite,通过IPC与React渲染进程通信才是正确思路。
具体实现步骤
1. 安装依赖
首先安装必要包,注意sqlite3需适配Electron版本,搭配electron-rebuild处理兼容性:
npm install sqlite3 --save npm install electron-rebuild electron-builder --save-dev
在package.json中添加postinstall脚本,确保每次安装依赖后自动重建sqlite3:
"scripts": { "postinstall": "electron-rebuild", "start": "react-scripts start", "build": "react-scripts build", "electron:start": "electron .", "electron:build": "npm run build && electron-builder" }
2. 主进程配置SQLite与IPC通信
在Electron主入口文件(如main.js)中初始化数据库,并通过IPC暴露操作方法:
const { app, BrowserWindow, ipcMain } = require('electron'); const sqlite3 = require('sqlite3').verbose(); const path = require('path'); // 数据库存放在Electron用户数据目录,打包后可正常访问 const dbPath = path.join(app.getPath('userData'), 'app.db'); let db; function createWindow() { const mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: path.join(__dirname, 'preload.js'), contextIsolation: true, // 开启上下文隔离保证安全 nodeIntegration: false } }); // 开发环境加载React dev server,打包后加载本地静态文件 if (process.env.NODE_ENV === 'development') { mainWindow.loadURL('http://localhost:3000'); } else { mainWindow.loadFile(path.join(__dirname, 'build', 'index.html')); } } // 初始化数据库并创建示例表 function initDB() { db = new sqlite3.Database(dbPath, (err) => { if (err) console.error('数据库连接失败:', err.message); console.log('成功连接SQLite数据库'); db.run(`CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT UNIQUE NOT NULL )`); }); } // IPC处理查询用户请求 ipcMain.handle('get-users', () => { return new Promise((resolve, reject) => { db.all('SELECT * FROM users', [], (err, rows) => { if (err) reject(err); resolve(rows); }); }); }); // IPC处理添加用户请求 ipcMain.handle('add-user', (_, user) => { return new Promise((resolve, reject) => { db.run(`INSERT INTO users(name, email) VALUES(?, ?)`, [user.name, user.email], function(err) { if (err) reject(err); resolve({ id: this.lastID }); }); }); }); app.whenReady().then(() => { initDB(); createWindow(); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) createWindow(); }); }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') app.quit(); });
3. Preload脚本暴露API给React
创建preload.js,通过contextBridge安全地将IPC方法暴露给React渲染进程:
const { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeInMainWorld('electronDB', { getUsers: () => ipcRenderer.invoke('get-users'), addUser: (user) => ipcRenderer.invoke('add-user') });
4. React组件中调用数据库操作
在React组件中直接通过window.electronDB调用数据库方法:
import { useState, useEffect } from 'react'; function App() { const [users, setUsers] = useState([]); const [name, setName] = useState(''); const [email, setEmail] = useState(''); useEffect(() => { loadUsers(); }, []); const loadUsers = async () => { try { const userList = await window.electronDB.getUsers(); setUsers(userList); } catch (err) { console.error('加载用户失败:', err); } }; const handleAddUser = async (e) => { e.preventDefault(); if (!name || !email) return; try { await window.electronDB.addUser({ name, email }); setName(''); setEmail(''); loadUsers(); } catch (err) { console.error('添加用户失败:', err); } }; return ( <div style={{ padding: '20px' }}> <h1>离线用户管理</h1> <form onSubmit={handleAddUser} style={{ marginBottom: '20px' }}> <input type="text" placeholder="姓名" value={name} onChange={(e) => setName(e.target.value)} style={{ marginRight: '10px' }} required /> <input type="email" placeholder="邮箱" value={email} onChange={(e) => setEmail(e.target.value)} style={{ marginRight: '10px' }} required /> <button type="submit">添加用户</button> </form> <ul> {users.map(user => ( <li key={user.id}>{user.name} - {user.email}</li> ))} </ul> </div> ); } export default App;
5. 打包配置
在package.json中添加electron-builder配置,确保sqlite3被正确打包:
"build": { "appId": "com.your.app.id", "files": [ "build/**/*", "main.js", "preload.js", "node_modules/sqlite3/**/*" ], "win": { "target": "nsis" } }
运行npm run electron:build即可生成Windows exe安装包。
替代方案
- better-sqlite3:性能优于
sqlite3,支持同步API,代码更简洁,替换依赖后可沿用上述流程。 - IndexedDB + localForage:若数据量不大、无需复杂SQL查询,纯前端IndexedDB配合localForage封装,无需主进程操作,更轻量化。
内容的提问来源于stack exchange,提问作者Swapnil Mane
相关产品推荐
相关产品推荐

