Electron+React 搭建桌面应用
创建应用程序
创建 Electron 应用
使用 Webpack 创建新的 Electron 应用程序:
npm init electron-app@latest my-new-app -- --template=webpack
启动应用
npm start

设置 Webpack 配置
添加依赖包,确保可以正确使用 JSX 和其他 React 功能:
npm install --save-dev @babel/core @babel/preset-react babel-loader
修改配置文件:
// webpack.rules.js
module.exports = [// ... existing loader config ...{test: /\.jsx?$/,use: {loader: 'babel-loader',options: {exclude: /node_modules/,presets: ['@babel/preset-react']}}}// ... existing loader config ...
];

集成前端 React
添加 React 依赖
将基本的 React 包添加到 dependencies:
npm install --save react react-dom
集成 React 代码
现在可以开始在 Electron 中编写和使用 React 组件了。在 src/app.jsx 中编写 React 代码:
import * as React from 'react';
import { createRoot } from 'react-dom/client';const root = createRoot(document.body);
root.render(<h2>Hello from React!</h2>);
添加渲染进程
将 React 代码添加到渲染进程 src/renderer.js 中:
import './index.css';
import './app.jsx';
console.log('👋 This message is being logged by "renderer.js", included via webpack');
启动应用
npm start

主进程和渲染进程通信
在 Electron 中,渲染进程和主进程之间的通信需要通过预加载脚本 preload.js 来进行,preload.js 的作用就是作为渲染进程和主进程之间通信的桥梁。
渲染进程 -> 主进程
当用户在界面上点击最小化或者最大化,或者更改某些全局设置(如语言偏好、主题等)时,这些更改通常由渲染进程触发,但实际执行由主进程负责。在这种情况下,渲染进程调用主进程的方法以应用这些更改,但不需要等待主进程的回包,因为用户界面的响应可以立即更新,而不必等待设置保存的确认。
预加载脚本
在预加载脚本 preload.js 中定义双方通信方法,使用 ipcRenderer.send 将信息发往主进程:
// See the Electron documentation for details on how to use preload scripts:
// https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scriptsconst {contextBridge, ipcRenderer} = require('electron');contextBridge.exposeInMainWorld('my_app_name', {// 最小化minimize: () => {ipcRenderer.send('minimize')},// 最大化maximize: () => {ipcRenderer.send('maximize')}
})
渲染进程
在渲染进程中,使用 window.app_name.func_name 调用预加载脚本里的方法:
import * as React from 'react';
import { createRoot } from 'react-dom/client';const root = createRoot(document.body);
root.render(<div><button onClick={() => {window.my_app_name.minimize()}}>最小化</button><button onClick={() => {window.my_app_name.maximize()}}>最大化</button>
</div>);
主进程
在主进程中,使用 ipc.Main.on 监听事件,并执行具体操作:
const {app, BrowserWindow, ipcMain} = require('electron');
const path = require('node:path');let mainWindow;const createWindow = () => {// 创建浏览器窗口。mainWindow = new BrowserWindow({width: 800,height: 600,webPreferences: {preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY, // 预加载脚本,用于在主进程和渲染进程之间安全地共享数据},});// 加载应用的index.html。mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY);// 打开开发者工具。mainWindow.webContents.openDevTools();
};// .....其他代码.....// 监听来自渲染进程的'minimize'消息,最小化主窗口。
ipcMain.on('minimize', event => {mainWindow.minimize();
})// 监听来自渲染进程的'maximize'消息,最大化主窗口。
ipcMain.on('maximize', event => {mainWindow.maximize();
})
渲染进程 <-> 主进程
在 Electron 中,用户可能需要打开、保存或者删除文件。当用户点击一个按钮或者菜单项来执行这些操作时,渲染进程会向主进程发送一个消息,请求执行相应的操作。主进程接到消息后,调用系统API来完成文件操作,并将操作结果发送回渲染进程,渲染进程根据主进程的响应更新界面状态等。
预加载脚本
在预加载脚本 preload.js 中定义双方通信方法,使用 ipcRenderer.invoke 将信息发往主进程,并将结果返回到渲染进程:
// See the Electron documentation for details on how to use preload scripts:
// https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scriptsconst {contextBridge, ipcRenderer} = require('electron');contextBridge.exposeInMainWorld('my_app_name', {// 选择文件chooseFile: async () => {const path = await ipcRenderer.invoke('choose-file');return path;},
})
渲染进程
在渲染进程中,使用 window.app_name.func_name 调用预加载脚本里的方法:
import * as React from 'react';
import {createRoot} from 'react-dom/client';const root = createRoot(document.body);
root.render(<div><button onClick={() => {window.my_app_name.chooseFile().then(result => {console.log(result['filePaths'][0])alert(result['filePaths'][0])})}}>选择文件</button>
</div>);
主进程
在主进程中,使用 ipc.handle 监听事件,执行操作并将结果返回给预加载脚本:
const {app, BrowserWindow, ipcMain, dialog} = require('electron');
const path = require('node:path');let mainWindow;const createWindow = () => {// 创建浏览器窗口。mainWindow = new BrowserWindow({width: 800,height: 600,webPreferences: {preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY, // 预加载脚本,用于在主进程和渲染进程之间安全地共享数据},});// 加载应用的index.html。mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY);// 打开开发者工具。mainWindow.webContents.openDevTools();
};// .....其他代码.....// 监听来自渲染进程的'choose-file'消息,选择文件,并将结果返回给预加载脚本。
ipcMain.handle('choose-file', async (event, data) => {const result = await dialog.showOpenDialog(BrowserWindow.getFocusedWindow(), {properties: ['openFile']});return result
});
主进程 -> 渲染进程
Electron 应用启动时,有时候需要由主进程从本地存储或者服务器来加载应用的配置信息(窗口大小、位置、主题设置等)。主进程加载完设置后,通过单向通信将配置信息发送给渲染进程。渲染进程接收到配置信息后,根据这些信息调整界面布局或者样式。通常用于初始化或者更新应用的界面设置。
主进程
在主进程中,使用 mainWindow.webContents.send 将消息发送给预加载脚本:
const {app, BrowserWindow, ipcMain, dialog} = require('electron');
const path = require('node:path');let mainWindow;const createWindow = () => {// 创建浏览器窗口。mainWindow = new BrowserWindow({width: 800,height: 600,webPreferences: {preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY, // 预加载脚本,用于在主进程和渲染进程之间安全地共享数据},});// 加载应用的index.html。mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY);// 打开开发者工具。mainWindow.webContents.openDevTools();// 设置十秒钟后发送消息到渲染进程setTimeout(() => {mainWindow.webContents.send('message-from-main', 'Hello from main process!');}, 3000); // 10000 毫秒等于 10 秒
};// .....其他代码.....
预加载脚本
在预加载脚本 preload.js 中使用 ipcRenderer.on 监听消息,然后通过回调函数将消息传递给渲染进程:
// See the Electron documentation for details on how to use preload scripts:
// https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scriptsconst {contextBridge, ipcRenderer} = require('electron');contextBridge.exposeInMainWorld('my_app_name', {msgFromMain: (callback) => ipcRenderer.on('message-from-main', (event, message) => {callback(message);})
})
渲染进程
在渲染进程中,使用 useEffect 来监听消息并作出相应处理:
import React, { useEffect, useState } from 'react';const App = () => {const [messageFromMain, setMessageFromMain] = useState('');useEffect(() => {// 调用预加载脚本中暴露的 msgFromMain 方法window.my_app_name.msgFromMain((message) => {setMessageFromMain(message);});// 清理函数(可选),如果需要的话可以在这里注销监听器return () => {// 如果有必要的话,可以在这里注销监听器,但在这个例子中我们不需要,因为ipcRenderer.on会自动管理监听器的生命周期};}, []); // 确保这个 effect 只运行一次return (<div>{/* 显示从主进程接收到的消息 */}<p>{messageFromMain}</p></div>);
};export default App;
【1】React | Electron Forge
相关文章:
Electron+React 搭建桌面应用
创建应用程序 创建 Electron 应用 使用 Webpack 创建新的 Electron 应用程序: npm init electron-applatest my-new-app -- --templatewebpack 启动应用 npm start 设置 Webpack 配置 添加依赖包,确保可以正确使用 JSX 和其他 React 功能ÿ…...
基于Android的记单词App系统的设计与实现
博主介绍:✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇dz…...
ELK 企业级日志分析系统 简单介绍
目录 一 ELK 简介 1, elk 是什么 2,elk 架构图 3,elk 日志处理步骤 二 Elasticsearch 简介 1, Elasticsearch 是什么 2, Elasticsearch 的核心概念 3, Elasticsearch 的原理 三 Logstas…...
GET与POST:详述HTTP两大请求方法的语义、数据处理机制、安全特性与适用场景
GET和POST方法在HTTP请求中具有明确的角色分工和特性差异。GET适用于读取操作和不敏感数据的传递,强调可缓存性和安全性,而POST适用于写入操作和敏感数据的提交,提供了更大的数据承载能力和更强的隐私保护。本文详细介绍了GET与POST请求方法的…...
Unity Pro 2019 for Mac:专业级游戏引擎,助力创意无限延伸!
Unity Pro 2019是一款功能强大的游戏开发引擎,其特点主要体现在以下几个方面: 强大的渲染技术:Unity Pro 2019采用了新的渲染技术,包括脚本化渲染流水线,能够轻松自定义渲染管线,通过C#代码和材料材质&…...
C++设计模式:单例模式(十)
1、单例设计模式 单例设计模式,使用的频率比较高,整个项目中某个特殊的类对象只能创建一个 并且该类只对外暴露一个public方法用来获得这个对象。 单例设计模式又分懒汉式和饿汉式,同时对于懒汉式在多线程并发的情况下存在线程安全问题 饿汉…...
openssl3.2 - exp - zlib
文章目录 openssl3.2 - exp - zlib概述笔记命令行实现程序实现备注 - 压缩时无法base64压缩时无法带口令压缩实现 - 对buffer进行压缩和解压缩测试效果工程实现main.cppCOsslZlibBuffer.hCOsslZlibBuffer.cpp总结END openssl3.2 - exp - zlib 概述 客户端和服务端进行数据交换…...
【故事】无人机学习之旅
今天是清明假期最后一天,晚上在看无人机的东西,翻到了欣飞鸽的知乎主页,读了他的一些文章。虽不曾相识,但感觉我们有很多相似的经历,也想记录一下自己的无人机学习之旅。 青铜:从使用开源飞控开始 我在大…...
torch.mean()的使用方法
对一个三维数组的每一维度进行操作 1,dim0 a torch.Tensor([0, 1, 2, 3, 4, 5,6,7]).view(2, 2, 2) print(a) mean torch.mean(a, 0) print(mean, mean.shape) 输出结果: tensor([[[0., 1.], [2., 3.]], [[4., 5.], [6., 7.]]]) tensor([[2., …...
windows安装Redis,Mongo,ES并快速基本掌握开发流程
前言 这里只是一些安装后的基础操作,后期会学习更加深入的操作 基础操作 前言RedisRedis启动idea集成Redisjedis技术 Mongodbwindows版Mongodb的安装idea整合Mongodb ES(Elasticsearch)ESwindows下载ES文档操作idea整合ES低级别ES整合高级别ES整合 Redis Redis是…...
ruoyi-nbcio-plus基于vue3的flowable的自定义业务提交申请组件的升级修改
更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio 演示地址:RuoYi-Nbcio后台管理系统 http://122.227.135.243:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码:…...
掌握网络抓取技术:利用RobotRules库的Perl下载器一览小红书的世界
引言 在信息时代的浪潮下,人们对于获取和分析海量网络数据的需求与日俱增。网络抓取技术作为满足这一需求的关键工具,正在成为越来越多开发者的首选。而Perl语言,以其卓越的文本处理能力和灵活的特性,脱颖而出,成为了…...
典型新能源汽车热管理系统方案分析
目前行业具有代表性的热管理系统有PTC电加热方案、热泵方案(特斯拉八通阀热泵、吉利直接式热泵)、威马的柴油加热方案以及以理想为代表的插电式混动车方案。 小鹏P7整车热管理方案分析(PTC电加热方案) 小鹏P7作为小鹏汽车的第2款…...
使用Docker部署开源项目FreeGPT35来免费调用ChatGPT3.5 API
Vercel部署FreeGPT35有严重限制,玩玩就好,真用还是得docker。 限制原因: Vercel的流式响应并不是一开始写流,客户端就能立刻收到响应流,而是先写到一个缓冲区,当流关闭才一股脑的流式响应回来(不是实时流) 因此导致: …...
《Linux运维实战:Kylin V10操作系统开启安装软件保留缓存设置》
总结:整理不易,如果对你有帮助,可否点赞关注一下? 更多详细内容请参考:Linux运维实战总结 一、操作步骤 1、改系统/etc/yum.conf配置文件,开启安装软件保留缓存设置 [rootecs-90c2-0003 ~]# vim /etc/yum.…...
视频生成技术:从GAN到Latte
GANs Diffusion Model...
机器学习中的激活函数
激活函数存在的意义: 激活函数决定了某个神经元是否被激活,当这个神经元接收到的信息是有用或无用的时候,激活函数决定了对这个神经元接收到的信息是留下还是抛弃。如果不加激活函数,神经元仅仅做线性变换,那么该神经网…...
LinuxAndroid: 旋转编码器input输入事件适配(旋转输入)
rk3588s: 旋转编码器input输入事件适配 基于Android 12 kernel-5.10版本 参考文档: https://blog.csdn.net/szembed/article/details/131551950 Linux 输入设备调试详解(零基础开发)Rotary_Encoder旋转编码器驱动 通用GPIO为例 挂载input输…...
机器学习和深度学习-- 李宏毅(笔记与个人理解)Day10
Day 10 Genaral GUidance training Loss 不够的case Loss on Testing data over fitting 为什么over fitting 留到下下周哦~~ 期待 solve CNN卷积神经网络 Bias-Conplexiy Trade off cross Validation how to split? N-fold Cross Validation mismatch 这节课总体听下来比较…...
perl 交叉编译
前言 Perl是一种高级、通用、解释型、动态的编程语言。Perl设计的初衷是为了更好地处理文本处理任务,但随着时间的发展,现在它已经变成了一种强大的一般目的编程语言。Perl支持面向过程和面向对象的编程风格。 Perl的特点: 强大的字符串处…...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
