實現一個Electron中IPC通訊組件記錄

做用

做用:將electron的ipc通訊功能封裝成組件形式,當接收得主進程的ipc消息會自動更新redux中store中的數據,當用戶經過專門的方法修改store的時候,又會自動更新store而且把消息發送給主進程。這樣的好處是一些展現類的信息就不須要頻繁註冊事件,只須要組件綁定store就能夠。
使用示例:javascript

//使用示例
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'connected-react-router';
import type { Store } from '../reducers/types';
import Routes from '../Routes';
import { ConnectIPC } from '../components/ConnectIPC';

export default function Root(Props) {
	const { store, history } = Props;
	return (
		<Provider store={store}> //組件須要包裹在reduxProvider中,經過這種方式,將ipc和redux鏈接起來 <ConnectIPC> <ConnectedRouter history={history}> <Routes /> </ConnectedRouter> </ConnectIPC> </Provider>
	);
}
複製代碼

實現

思路:思路大體和ConnectedRouter組件的實現差很少,在ConnectIPC中,經過訂閱ipcRenderer的事件來獲取主進程發過來的消息,經過訂閱redux中store的subscribe來獲取用戶主動發送的數據。
遇到的問題:
一、如何獲取store到ConnectIPC中?
React提供了一個提供者模式,這個模式的使用以下:java

import { createContext } from 'react';

let { Provider, Consumer } = createContext();
//被IPCProvider包裹的子組件均可以經過IPCConsumer利用render props模式獲取到值
export let IPCProvider = Provider;
export let IPCConsumer = Consumer;
複製代碼

Redux也提供了相似的方式react

//經過這種方式獲取到Redux的提供者上下文
import { ReactReduxContext } from 'react-redux';
複製代碼

將store注入到組件中去redux

function ConnectIPCWithContext(props) {
		let Context = props.context || ReactReduxContext;
		if (Context == null) {
			throw 'Please upgrade to react-redux v6';
		}
		return <Context.Consumer>{({ store }) => <ConnectIPC store={store} {...props} />}</Context.Consumer>;
	}
複製代碼

二、如何實現子組件被ConnectIPC包裹,而且實現偵聽改變state 如下是ConnectIPC的實現react-router

class ConnectIPC extends Component {
		constructor(props) {
			super(props);
			//獲取上面ConnectIPCWithContext組件注入進來的store onIPCRenderMessage是action方法經過React-Redux的connect組件注入進來的。
			let { store, onIPCRenderMessage, children } = props;
			//返回卸載方法,偵聽
			//註冊IPC事件,wrapIpcRender方法裏面註冊事件,而且將取消事件的方法返回來,能夠在組件生命週期卸載的時候,取消註冊。
			this.unipcRender = wrapIpcRender((event, arg) => {
				//接受消息
				onIPCRenderMessage(arg);
			});
			this.lastSendMsg = {};
			//當用戶主動向主進程發送數據的時候,也應該是經過操做store,爲了防止數據重複發送,因此每一次的數據都會有uuid保證惟一。
			this.unSubScribe = store.subscribe(() => {
				//偵聽數據變動
				//判斷數據變動
				//對象的比較問題
				console.log(`偵聽`)
				let { sendMsg } = store.getState();
				//判斷uuid
				// if (this.lastSendMsg.uuid === sendMsg.uuid) {
				// 	return;
				// }
				//發送信息到ipc
				ipcRenderer.send('channel', sendMsg);
				// this.lastSendMsg = sendMsg;
			});
			//提供給用戶的修改store的方法,sendIPCRenderMessage是個action,用來觸發修改數據
			this.wrapIpcRendererMsg = wrapIpcRendererMsg(store, sendIPCRenderMessage);
		}
        //卸載事件
		componentWillUnmount() {
			this.unipcRender();
			this.unSubScribe();
		}

		render() {
			let { children } = this.props;
			return (
			//使用IPC的提供者包裹子組件
				<IPCProvider value={{ sendIpcRendererMsg: this.wrapIpcRendererMsg }}>
				//保證子組件惟一
					{React.Children.only(children)}
				</IPCProvider>
			);
		}
	}
	
	
}
    //wrapIpcRender函數實現
	import {ipcRenderer} from 'electron'

         export  function wrapIpcRender(cb){
             ipcRenderer.on('channel',cb);
                  return function(){
             ipcRenderer.removeListener('channel',cb);
         }
         
         export function wrapIpcRendererMsg(store,action){
  // ipcRenderer.send(msg)
         return (args)=>{
         // console.log( `所有數據是${JSON.stringify(store.getState())}`)
         store.dispatch(action(args));
  }
}
複製代碼

三、如何對有須要的組件注入sendIpcRendererMsg方法?
使用高階組件相似Redux的connect,補充知識點是ES6的類裝飾器函數若是返回不爲false的值那個調用這個類的時候使用的就是這個值。
如下是注入的實現和使用electron

//實現
export function connectIPCSender() {
	return (Component) => (props) => (
	//使用ipc得到提供者的數據
		<IPCConsumer>
		//將方法輸入到子組件,可是高階組件的規則是保證無關props的傳遞,因此須要再把props傳遞過去
			{({ sendIpcRendererMsg }) => <Component sendIpcRendererMsg={sendIpcRendererMsg} {...props} />} </IPCConsumer>
	);
}
//使用對一個標題欄注入sendIpcRendererMsg方法
/注入ipc通訊
@connectIPCSender()
export default class Heade extends Component{
  render(){
    console.log(this.props)
    let {sendIpcRendererMsg}=this.props;
    return (
      <div onClick={()=>{console.log('dianji'); sendIpcRendererMsg(Date.now())}} className={styles.heade}> </div>
    )
  }
}
複製代碼

概念性的東西

這其中主要用到的概念仍是React文檔中的那一套
一、高階組件
二、Render Props
三、提供者模式
四、函數柯里化
ide

相關文章
相關標籤/搜索