Setup electron+ React + TS environment

The starting project for this article (note the 1.base_env branch): github.com/Licht-club/…

Because this is a continuation of the previous section, of course, this section and the previous section is not necessarily related

This article covers document summarization

IpcMain Main process ipcRenderer render process webContents

Summary of interaction modes

The main thread

The render thread

Interactive mode

ipcMain.handle

ipcRenderer.invoke

Renderer request + main process response

webContents.send

ipcRenderer.on

Main process push

ipcMain.on

ipcRenderer.send

The renderer initiates the request

Our start-up project

We want to complete the function: simulation implementation of a remote control client 1. Simulation rendering thread to achieve login, obtain their control code 2. Simulate requests to control a user’s window

The render thread implements login

  1. Modify the React page to add a login button

/render-process/main/index.tsx

import React, {useEffect, useState} from 'react' import ReactDom from 'react-dom' import { ipcRenderer } from 'electron' const App = () => { const  [localCode,setLocalCode]=useState(''); Const login =async () => {const login =async () => {const login =async () => { Const code=await ipcrenderer.invoke ('login') // Store control code setLocalCode(code)} return <div> <div>hello react</div> {localCode? {localCode} </div>: <button onClick={()=>login()}> </button>} </div>} reactdom.render (<App></App>, document.getelementbyid ('root'))Copy the code

Here ipcrenderer. invoke, Send a message to the main process via channel and expect a result asynchronously are used.

  1. The main thread responds to the login request

Main-process /ipc.ts encapsulates a function that handles transactions for the main process

Import {ipcMain} from 'electron' export function ipc(){ipcmain.handle ('login',async ()=>{// mock a status code const code=Math.floor(Math.random()*(999999-100000))+100000; return code; })}Copy the code

The main-process/index.ts main entry calls the function before creating the window

import {app, BrowserWindow} from 'electron' import {create} from './mainWindow' import {ipc} from "./ipc"; app.on('ready', () => { process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'; // Disable web security warning ipc() create()})Copy the code

Reboot Electron to see what happens

rendering

Before landing:

After landing:

conclusion
// invoke ipcrenderer.invoke ('some-name', someArgument). Then (result) => {//... }) // Main process responds to ipcmain. handle('some-name', async (event, someArgument) => { const result = await doSomeWork(someArgument) return result })Copy the code

Request control of a user window

/render-process/main/index.tsx adds an input and a button, omitting the local code

Function App(){const startControl = (remoteCode:string)=>{ipcrenderer.send ('control',remoteCode)} return <div> <div>hello react</div> {localCode? {localCode} </div>: <button onClick={()=>login()} </button>} <input type="text" value={remoteCode} <button onClick={()=>startControl(remoteCode)}> </button> </div>}Copy the code

The second argument to the ipcmain. on function is a callback function. Ts correctly identifies the type of the ipcmain. on function

Import {ipcMain} from 'electron' export function ipc(){ipcmain.handle ('login',async ()=>{// mock a status code const code=Math.floor(Math.random()*(999999-100000))+100000; return code; }) ipcmain. on('control',async(e,remoteCode:string)=>{console.log(remoteCode,' master received control code ')})}Copy the code

The main thread received the request successfully, and our composition is complete

Finish the renderings

conclusion

If you want to receive a single response from the main process, such as the result of a method call, consider using ipCrenderer.invoke. Ipcrenderer.send is used for purely pushing and transmitting push data

// Renderer process pushes ipcrenderer. send('some-name',... Args) // Main process Listen on ipcmain. on('some-name', async (... args) => { })Copy the code

The main thread pushes the render thread

Main-process/mainwindow. ts adds a send function that can be used anywhere in the main thread to push information to the renderer thread

import {BrowserWindow} from 'electron' import isDev from 'electron-is-dev' import {resolve} from 'path' let win: BrowserWindow; export function create() { // ... } export function send(channel:string,... args:any[]){ win.webContents.send(channel,... args) }Copy the code

Main-process/IPc.ts pushes a Control-state-change to the renderer thread upon receiving a request from the renderer process

import {ipcMain} from 'electron' import {send} from './mainWindow' export function ipc(){ ipcMain.handle('login',async ()=>{// mock a state code const code= math.floor (math.random ()*(99999-100000))+100000; return code; }) ipcmain. on('control',async(e,remoteCode:string)=>{ But the mock returns send('control-state-change',remoteCode,1)})}Copy the code

The next step is to listen for Control-state-change in the rendering thread and add a listener in the useEffect lifecycle, much the same as adding a listener to the DOM

render-process/main/index.tsx

import React, {useEffect, useState} from 'react' import ReactDom from 'react-dom' import {ipcRenderer, IpcRendererEvent} from 'electron' const App = () => { const [localCode,setLocalCode]=useState(''); Const [remoteCode,setRemoteCode]=useState("); // Const [remoteCode,setRemoteCode]=useState("); / / other users' control code const [controlText setControlText] = useState ("); / / control code copy const handleControlState = (e: IpcRendererEvent, name: string, type: number) = > {let text = ' '; ${name} '} setControlText(text) ${name} '} setControlText(text)} useEffect(()=>{ Ipcrenderer. on('control-state-change',handleControlState) return ()=>{ Best to remove this function (exit) ipcRenderer. RemoveListener (' control - state - change, handleControlState)}})/login/simulation function const login = async () => {// Obtain the control code after login // because the login status is maintained in the main process, Invoke ('login') // Store control code setLocalCode(code)} const startControl = Ipcrenderer. send('control',remoteCode)} return <div> <div>hello react</div> {localCode? {localCode} </div>: <button onClick={()=>login()}> </button>} <div> {controlText} </div> <input type="text" value={remoteCode} <button onClick={()=>startControl(remoteCode)}> </button> </div>} ReactDom.render(<App></App>, document.getElementById('root'))Copy the code

The rendering thread completes the listening

Finish the renderings

Emulation opens a controlled window

Render \control\index.html Opens a new HTML

<! doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, User - scalable = no, initial - scale = 1.0, the maximum - scale = 1.0, Minimum scale=1.0"> <meta HTTP-equiv =" x-UA-compatible "content=" IE =edge"> <title>Document</title> </head> <body> <div> under control </div> </body> </ HTML >Copy the code

main-process\controlWindow.ts

import {BrowserWindow} from 'electron' import {resolve} from 'path' let win; export function createControlWindow() { win=new BrowserWindow({ width:800, height:800, webPreferences:{ nodeIntegration:true } }) win.loadFile(resolve(__dirname,'.. /render-process/control/index.html')) }Copy the code

main-process\ipc.ts

The main thread receives control and opens a new window

Import {createControlWindow} from './controlWindow' export function ipcHandle() {// ipcmain.handle The main thread responds to the rendering thread ipcMain.handle('login',()=>{ let code=Math.floor(Math.random()*(999999-100000))+100000; Console. log(code,' mainline generated code') return code}) ipcmain. on('control',(e,remoteCode)=>{ send('control-state-change',remoteCode,1) createControlWindow() }) }Copy the code

Final rendering

Git git git git git git git git git git

https://github.com/Licht-club/react-electron/tree/2.mainWithRender
Copy the code