实现一个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

相关文章
相关标签/搜索