You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 15:53:11