DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 963,673 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Cover image for Electron Router DOM is here!
Dalton Menezes
Dalton Menezes

Posted on

Electron Router DOM is here!

If you've already tried using react-router-dom with Electron, had difficulties getting it to work both in development and in production and in different windows, this library is for you πŸš€

Features

  • πŸš€ Ready for Development and Production environments
  • πŸ”₯ Works on Multiple windows
  • πŸ“¦ Isolated routes by window id

Installation

In your terminal, run:

yarn add electron-router-dom

# OR

npm i electron-router-dom
Enter fullscreen mode Exit fullscreen mode

Router DOM is a peer dependency, if you haven't installed it yet or your package manager won't handle it automatically for you, so run:

yarn add react-router-dom

# OR

npm i react-router-dom
Enter fullscreen mode Exit fullscreen mode

Usage

The main thing to keep in mind is: you must use the same window id in the Electron Main Process used in createFileRoute and createURLRoute functions and in the Electron Renderer Process in the <Router> component prop names.

Electron Main Process

import {
  app,
  BrowserWindow,
  BrowserWindowConstructorOptions as WindowOptions,
} from 'electron'

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

function createWindow(id: string, options: WindowOptions = {}) {
  const window = new BrowserWindow({
    width: 700,
    height: 473,
    ...options,
  })

  const devServerURL = createURLRoute(process.env['ELECTRON_RENDERER_URL']!, id)

  const fileRoute = createFileRoute(
    join(__dirname, '../renderer/index.html'),
    id
  )

  process.env.NODE_ENV === 'development'
    ? window.loadURL(devServerURL)
    : window.loadFile(...fileRoute)

  return window
}

app.whenReady().then(() => {
  createWindow('main', {
    webPreferences: {
      preload: join(__dirname, '../preload/index.js'),
    },
  })

  createWindow('about', {
    width: 450,
    height: 350,
    show: false,
  })
})
Enter fullscreen mode Exit fullscreen mode

Electron Renderer Process

Create a routes.tsx file:

import { Router, Route } from 'electron-router-dom'

import { MainScreen, AboutScreen, SearchScreen } from './screens'

export function AppRoutes() {
  return (
    <Router
      main={
        <>
          <Route path="/" element={<MainScreen />} />
          <Route path="/search" element={<SearchScreen />} />
        </>
      }
      about={<Route path="/" element={<AboutScreen />} />}
    />
  )
}
Enter fullscreen mode Exit fullscreen mode

Then, import the AppRoutes in your index.tsx:

import ReactDom from 'react-dom/client'
import React from 'react'

import { AppRoutes } from './routes'

ReactDom
  .createRoot(document.querySelector('app') as HTMLElement)
  .render(
    <React.StrictMode>
      <AppRoutes />
    </React.StrictMode>
  )
Enter fullscreen mode Exit fullscreen mode

A simple example of a MainScreen component:

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

// The "App" comes from the context bridge in preload/index.ts
const { App } = window

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

  return (
    <main>
      <button onClick={() => navigate('/search')}>Go to Search screen</button>

      <button onClick={App.OpenAboutWindow}>Open About window</button>
    </main>
  )
}
Enter fullscreen mode Exit fullscreen mode

To get more knowledge about this library, please,
check the Electron Router DOM GitHub Repository

Thanks πŸ’œ

Top comments (1)

Need a better mental model for async/await?

Check out this classic DEV post on the subject.

β­οΈπŸŽ€ JavaScript Visualized: Promises & Async/Await

async await