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
- 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.
- 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