Electron+React必看:electron-router-dom 完整实战指南(含路由守卫/传参/多窗口)

0 阅读5分钟

做过 Electron + React 桌面端开发的兄弟,大概率都被路由兼容坑惨过:原生 react-router-dom 在开发环境跑得溜,打包生产直接失效;多窗口场景下路由互相污染,关窗还残留历史栈;开发/生产环境加载逻辑不一致,调试到头秃。

今天带来 electron-router-dom 完整版教程,基于官方入门文扩展,不仅保留基础上手流程,还把路由守卫、动态传参、嵌套路由、生产优化、底层逻辑一次性讲透,10年桌面端开发踩坑经验全塞进去,复制代码直接落地。

核心定位:react-router-dom 官方适配器,专为 Electron 多窗口、开发/生产双环境定制

核心解决:环境兼容、多窗口路由隔离、路由污染、生产失效四大痛点

一、先搞懂:为什么原生 react-router-dom 不适配 Electron?

很多人直接把网页路由搬到 Electron,踩坑了都不知道原因。底层逻辑很简单:

  • 网页是单窗口、hash/history 路由模式,Electron 多窗口是独立渲染进程,路由状态无法隔离
  • 开发环境用 localhost 服务,生产环境加载本地 HTML 文件,路由路径解析规则不一致
  • 原生路由没有窗口 ID 绑定,多窗口共用一个路由栈,导致跳转混乱、内存泄漏

electron-router-dom 就是做了一层封装:通过窗口 ID 绑定路由,让每个窗口拥有独立路由栈,自动适配开发/生产环境的路径解析,完美兼容 react-router-dom 原有 API(useNavigate、useParams 等)。


二、完整安装流程(含依赖避坑)

该库依赖 react-router-dom,必须同步安装,别漏装导致启动报错:

# npm 安装
npm i electron-router-dom react-router-dom

# yarn 安装
yarn add electron-router-dom react-router-dom

# pnpm 安装(推荐)
pnpm add electron-router-dom react-router-dom

重点提醒:react-router-dom 必须是 v6 版本(v5 不兼容),当前主流项目都是 v6,直接安装即可。

三、主进程全配置(开发/生产双环境+多窗口)

主进程核心是创建窗口 + 绑定窗口 ID + 区分环境加载路由,这步是路由生效的关键,窗口 ID 必须和渲染进程严格对应,不能错!

import { app, BrowserWindow, BrowserWindowConstructorOptions } from 'electron'
import { createFileRoute, createURLRoute } from 'electron-router-dom'
import { join } from 'path'

// 封装创建窗口函数,id 为路由唯一标识
function createWindow(id: string, options: BrowserWindowConstructorOptions = {}) {
  const window = new BrowserWindow({
    width: 700,
    height: 473,
    ...options,
    // 推荐开启,避免白屏
    show: false,
    webPreferences: {
      preload: join(__dirname, '../preload/index.js'),
      // 关闭跨域限制(桌面端常用)
      webSecurity: false,
      nodeIntegration: false,
      contextIsolation: true
    }
  })

  // 开发环境:加载本地服务路由
  const devURL = createURLRoute(process.env.ELECTRON_RENDERER_URL!, id)
  // 生产环境:加载本地 HTML 文件路由
  const prodRoute = createFileRoute(join(__dirname, '../renderer/index.html'), id)

  // 环境区分加载
  if (process.env.NODE_ENV === 'development') {
    window.loadURL(devURL)
  } else {
    window.loadFile(...prodRoute)
  }

  // 页面加载完毕再显示,避免闪烁
  window.once('ready-to-show', () => window.show())
  return window
}

// 应用就绪后创建窗口
app.whenReady().then(() => {
  // 主窗口,id = main
  createWindow('main')
  // 关于窗口,id = about
  createWindow('about', { width: 450, height: 350 })
})

// 关闭所有窗口退出(mac 除外)
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') app.quit()
})

四、渲染进程路由配置(基础+嵌套+多窗口)

渲染进程通过 Router 组件按窗口 ID 配置路由,和主进程 ID 一一对应,支持嵌套路由、路由分组。

1. 路由配置文件(routes.tsx)

import { Router, Route } from 'electron-router-dom'
// 引入页面组件
import { MainScreen, SearchScreen, AboutScreen, UserDetailScreen } from './screens'
// 引入路由守卫组件
import { AuthGuard } from './guards/AuthGuard'

export function AppRoutes() {
  return (
    <Router
      // 主窗口路由id=main),支持嵌套/多路由
      main={
        <>
          {/* 基础路由 */}
          <Route path="/" element={<MainScreen />} />
          {/* 带路由守卫的路由(需登录) */}
          <Route path="/search" element={<AuthGuard><SearchScreen /></AuthGuard>} />
          {/* 动态传参路由 */}
          <Route path="/user/:id" element={<UserDetailScreen />} />
        </>
      }
      // 关于窗口路由(id=about),独立路由栈
      about={<Route path="/" element={<AboutScreen />} />}
    />
  )
}

2. 入口文件挂载路由(index.tsx)

import React from 'react'
import ReactDOM from 'react-dom/client'
import { AppRoutes } from './routes'

const root = ReactDOM.createRoot(document.getElementById('root')!)
root.render(
  <React.StrictMode>
    <AppRoutes />
  </React.StrictMode>
)

五、核心进阶用法(原文缺失,必看)

1. 路由跳转(useNavigate 用法)

和原生 react-router-dom 完全一致,直接复用原有写法,无需改逻辑:

import { useNavigate } from 'react-router-dom'

export function MainScreen() {
  const navigate = useNavigate()

  return (
    <main style={{ padding: '20px' }}>
      <h1>主窗口</h1>
      {/* 普通跳转 */}
      <button onClick={() => navigate('/search')}>跳转搜索页</button>
      {/* 动态传参跳转 */}
      <button onClick={() => navigate('/user/1001')}>查看用户详情</button>
      {/* 返回上一页 */}
      <button onClick={() => navigate(-1)}>返回</button>
    </main>
  )
}

2. 动态路由参数获取(useParams)

import { useParams } from 'react-router-dom'

export function UserDetailScreen() {
  // 获取路由上的 id 参数
  const { id } = useParams<{ id: string }>()

  return (
    <div>
      <h2>用户详情页</h2>
      <p>用户ID:{id}</p>
    </div>
  )
}

3. 路由守卫(权限控制,登录拦截)

封装高阶组件,实现未登录跳转登录页,桌面端权限控制必备:

// src/guards/AuthGuard.tsx
import { Navigate } from 'react-router-dom'

interface AuthGuardProps {
  children: React.ReactNode
}

export function AuthGuard({ children }: AuthGuardProps) {
  // 判断登录状态(可从 store/preload 读取)
  const isLogin = localStorage.getItem('token') ? true : false

  // 未登录跳转首页
  if (!isLogin) return <Navigate to="/" replace /&gt;
  // 已登录放行
  return children
}

4. 多窗口通信 + 路由联动

通过 preload 暴露方法,主进程打开新窗口,渲染进程触发,路由自动隔离:

// 页面组件内调用
const { App } = window // preload 暴露的 API
<button onClick={() => App.openAboutWindow()}>打开关于窗口</button>

六、生产打包避坑(关键!)

  • 打包前务必校验 窗口 ID 一致性,主进程和渲染进程必须完全匹配
  • 生产环境关闭 devTools,路由文件路径别写错,避免加载失败
  • 路由不要用绝对路径,统一用相对路径,防止跨域/文件找不到
  • 多窗口关闭时,同步清理路由状态,避免内存泄漏

七、底层逻辑简析(看懂不踩坑)

electron-router-dom 本质是路由分发器

  1. 主进程通过窗口 ID 标记路由,开发环境拼接 URL,生产环境拼接文件路径
  2. 渲染进程通过 ID 匹配对应路由组,每个窗口路由栈独立,互不干扰
  3. 内部兼容 react-router-dom v6 核心 API,上层写法无感知,底层做环境适配

八、总结

electron-router-dom 是 Electron + React 开发的路由神器,解决了原生路由最头疼的环境和多窗口问题。基础用法简单易上手,进阶用法(守卫、传参、嵌套)完全兼容 react-router-dom,上手成本极低。

建议大家把这份教程收藏,项目里直接复制配置,再也不用折腾路由兼容问题。如果碰到窗口白屏、路由失效,优先检查窗口 ID 是否一致、环境路径是否正确,90% 的坑都能解决。

点赞+收藏,Electron 开发少走一周弯路,需要完整项目模板的评论区留言~