如何与Electron一起使用React路由器

How to use React Router with Electron?

本文关键字:React 路由器 一起 Electron      更新时间:2024-03-25

使用这个样板作为参考,我创建了一个Electron应用程序。它使用webpack来捆绑脚本和express服务器来托管它

Webpack配置实际上与此和服务器配置相同。

Electron的脚本加载:

mainWindow.loadURL('file://' + __dirname + '/app/index.html');

index.html加载服务器托管的脚本:

<script src="http://localhost:3000/dist/bundle.js"></script>

我运行electron index.js来构建应用程序,运行node server来启动使用webpack捆绑脚本的服务器。

它运行良好,我的React组件应用程序已安装。但我如何将react路由器集成到其中呢?

我实现它的方式与在浏览器应用程序中实现的方式相同。我得到这个错误:

[react-router] Location "/Users/arjun/Documents/Github/electron-app/app/index.html" did not match any routes

它以文件路径作为路由。仔细检查锅炉铭牌代码也无济于事。我错过了什么?

必须用HashRouter替换BrowserRouter

import {
  HashRouter,
  Route
} from "react-router-dom";

然后在我的index.js或Electron应用程序的输入文件中,我有这样的东西:

<HashRouter>
  <div>
    <Route path="/" exact     component={ Home } />
    <Route path="/firstPage"  component={ FirstPage } />
    <Route path="/secondPage" component={ SecondPage } />
  </div>
</HashRouter>

然后一切都正常了。

理由是:BrowserRouter适用于基于请求的环境,而HashRouter适用于基于文件的环境。

点击此处阅读更多:

  • https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/docs/api/HashRouter.md

另一个选项是使用hashHistory。事实上,在您引用的回购中,您可以看到他们正在使用hashHistory,不如尝试一下并发布回去?

我使用的是React Router v4,不想回退到HashRouter,所以我用以下方法解决了这个问题:

import { Redirect, BrowserRouter } from 'react-router-dom';
const App = () => (
  <BrowserRouter>
    <div>
      {window.location.pathname.includes('index.html') && <Redirect to="/" />}
    </div>
  </BrowserRouter>
);

在回答这个问题时,最好的选择是使用MemoryRouter,对我有用:)

(当前)反应路由器文档说:

一般来说,您应该使用<浏览器路由器>如果您具有响应请求的服务器,并且<哈希路由器>如果您使用的是静态文件服务器。

Electron应用程序基本上是一个静态文件服务器。

MemoryRouter也可以工作,只要所有路由都源于应用程序的React部分。只有当您想从浏览器进程导航到特定页面时,它才会下降,例如,您想弹出一个新窗口并直接导航到"常规首选项"页面。在这种情况下,可以使用HashRouter:

prefsWindow.loadURL(`file://${__dirname}/app/index.html#/general-prefs`);

我认为MemoryRouter(从浏览器进程)没有办法做到这一点。

简单地使用Switch默认为"/",如下所示:

<Switch>
  <Route path="/" exact component={Home}/>
  <Route path="/foo" component={Foo}/>
  <Route path="/bar" component={Bar}/>
  <Route render={() => <Redirect to="/"/>}/>
</Switch>

这样,"/index.html"将重定向到"/"

同意Niekert的意见。但我相信,在进行任何路线管理之前,最好先这样处理。

if ( window.location.pathname.includes('index.html') ) {
    location.pathname = ROUTES.ROOT;
}

这完全取决于传递给mainWindow.loadURL的URL类型。

file://...

如果通过file://协议直接加载index.html,例如

mainWindow.loadURL('file://' + path.join(__dirname, '../index.html#/home'))

那么您需要使用HashRouter:

<HashRouter>
  <Routes>
    <Route path='/home' element={<MyHomeScreen/>}>
  </Routes>
</HashRouter>

请注意,index.html#/home中的#是非常重要的!

为什么?

想想如果你写index.html/home会发生什么。您的计算机将尝试在index.html目录中检索home文件。#防止了这种情况,因此我们需要使用Hash路由器。

http://localhost:3000

如果从localhost:3000等服务器加载index.html,则有两个选项:

  • 包括#,如
    mainWindow.loadURL('http://localhost:3000#/home')
    
    并且完全如上所述使用CCD_ 27

  • 不包括#,如
    mainWindow.loadURL('http://localhost:3000/home')
    
    并像这样使用CCD_ 29:
    <BrowserRouter>
      <Routes>
        <Route path='/home' element={<MyHomeScreen/>}>
      </Routes>
    </BrowserRouter>
    

在这种情况下,许多人更喜欢使用BrowserRouter,因为它避免了#使URL复杂化。

在您的main过程中:

mainWindow.loadURL(resolveHtmlPath('index.html'));

在您的renderer流程中:

import { HashRouter as Router, Routes, Route } from 'react-router-dom';
//...
<Router>
  <Routes>
    <Route path="/" element={<Home />} />
    <Route path="/search" element={<Search />} />
    <Route
      path="/library"
      element={<Library />}
      />
  </Routes>
</Router>

resolveHtmlPath的调用消除了对我使用标签的需要。在开发工具中使用开箱即用的BrowserRouter给了我警告消息。

这个功能在你提到的Electron React Boilerplate项目中:

import { URL } from 'url';
import path from 'path';
export function resolveHtmlPath(htmlFileName: string) {
  if (process.env.NODE_ENV === 'development') {
    const port = process.env.PORT || 1212;
    const url = new URL(`http://localhost:${port}`);
    url.pathname = htmlFileName;
    return url.href;
  }
  return `file://${path.resolve(__dirname, '../renderer/', htmlFileName)}`;
}