Electron学习之旅1,进程间的通讯,React Hook 自定义Hook,React HOC,electron-is-dev,concurrently + wait-on + cross-env

一、基础知识

1、进程与线程
内存使用方面
通信机制方面
量级方面

2、使用nodemon重启动工程

"dev": "nodemon --watch main.js --exec electron ."

3、安装devtron
cnpm i devtron -D

// 在main.js中
app.on('ready', () => {
  require('devtron').install(); // 安装devtron
  let mainWindow = new BrowserWindow({
		// ...
  });
  mainWindow.loadFile('index.html');
  mainWindow.webContents.openDevTools(); // 开启调试工具
});

4、进程间的通讯

方式一、IPC,ipcMain ipcRenderer 渲染进程 -> 主进程(个性化需求的通讯)
// renderer.js 1、渲染进程 向 主进程发消息
const { ipcRenderer } = require('electron');
ipcRenderer.send('message2', 'hello from renderer.js');
ipcRenderer.on('reply2',(event, arg) => { ... }) // 4、渲染进程接收主进程的回复

// main.js 主进程 接收消息
const { app, BrowserWindow, ipcMain } = require('electron');
ipcMain.on('message2', (event, arg) => { // 2、主进程接收渲染进程消息
  console.log(event);
  console.log(arg); // 消息
  event.reply('reply2', 'from main God') // 3、主进程回复渲染进程
});
方式二、remote // 渲染进程获取主进程API(实质是ipc通讯封装集)
// renderer.js 渲染进程中
const { BrowserWindow } = require('electron').remote; 

// 注:remote其实是electron内部实现的消息通讯,方便我们开发者使用

方式三、webContents // 主进程->渲染进程

Electron学习之旅1,进程间的通讯,React Hook 自定义Hook,React HOC,electron-is-dev,concurrently + wait-on + cross-env_第1张图片
渲染进程中:
Electron学习之旅1,进程间的通讯,React Hook 自定义Hook,React HOC,electron-is-dev,concurrently + wait-on + cross-env_第2张图片

方式四、主进程 -> 主进程

使用Emitter事件
菜单项回调,需要主进程,创建第二个渲染进程。
Electron学习之旅1,进程间的通讯,React Hook 自定义Hook,React HOC,electron-is-dev,concurrently + wait-on + cross-env_第3张图片
main.js 接收emit事件
Electron学习之旅1,进程间的通讯,React Hook 自定义Hook,React HOC,electron-is-dev,concurrently + wait-on + cross-env_第4张图片

React Hook // 返回带有react特性的函数(返回正常组件或特性值)

Hook: 无需修改组件结构情况下,复用状态逻辑。

1、useState 组件状态

Hook就是能让函数钩入react特性的函数。

import React, { useState, Fragment } from 'react';

const LikeButton = () => {
  const [like, setLike] = useState(0); // react特性state
  const [on, setOn] = useState(true);
  return (
    <Fragment>
      <button onClick={() => on && setLike(like + 1)}>
        {like}:★
      </button>
      <button onClick={() => setOn(!on)}>
        {on ? '开启' : '关闭'}
      </button>
    </Fragment>
  )
};

export default LikeButton;
2、useEffect 渲染Hook// 发生每次在渲染之后

1、每次渲染都会执行

import React, { useState, useEffect } from 'react';
// 函数内部
useEffect(() => {
  document.title = `点击了${like}次`
});

2、可以return一个函数,去清理监听事件,避免监听事件累加。

import React, { useState, useEffect } from 'react';
// ...
useEffect(() => {// 渲染时执行
  console.log('add listener');
  const updateMouse = (event) => {
    setPos({ x: event.clientX, y: event.clientY })
    console.log('inner');
  } 
  return () => {// return 会在第二次渲染执行,(清除)第一次的内容
    console.log('remove listener');
    document.removeEventListener('click', updateMouse);
  }
};

3、第二个参数可以传递一个数组,表示渲染的依赖的state或prop(传递进来的变量)。

useEffect(() => {
  setLoading(true);
  axios.get('https://dog.ceo/api/breeds/image/random').then(result => {
    setUrl(result.data.message);
    setLoading(false);
  })
}, [fetch]);// [] 告诉react你的effect的渲染依赖于数组中含有的props或者state

总结: useEffect Hooc
// 1、不加参数,相当于DidUpdate,每次触发。
// 2、若第二个参数为空,则只渲染一次相当于DidMount,触发一次。
// 3、若第二个参数有数据,相当于DidUpdate,依于state和props,条件触发。
// 4、函数中return一个函数,会在第二次渲染触发,可以用于清除监听事件。

3、自定义Hook // 必须以use…命名

事件添加在DOM节点上,逻辑和表现,即control和view本身没有任何关系,可以使用自定义hook。

// hooks/useMousePos.js
import React, { useState, useEffect } from 'react';

const useMousePos = () => {
  const [pos, setPos] = useState({ x: 0, y: 0 });
  useEffect(() => {// 渲染时执行
    const updateMouse = (event) => {
      setPos({ x: event.clientX, y: event.clientY })
    }
    document.addEventListener('mousemove', updateMouse);
    return () => {// return 会在第二次渲染执行,(清除)第一次的内容
      document.removeEventListener('mousemove', updateMouse);
    }
  });
  return pos; // 返回值让需要的组件调用即可。
}

export default useMousePos;

React HOC // 返回包装过的新组件

先看个hoc例子

import React from 'react';
import axios from 'axios';

const withLoader = (WrappedComponent, url) => {
  return class LoaderComponent extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        data: null,
        isLoading: false
      }
    }

    componentDidMount() {
      this.setState({
        isLoading: true
      });
      axios.get(url).then(result => {
        this.setState({
          data: result.data,
          isLoading: false
        })
      });
    }

    render() {
      const { data, isLoading } = this.state;
      return (
        <>
          {(isLoading || !data) ? <p>data is loading...</p>
            : <WrappedComponent {...this.props} data={data} isLoading={isLoading} />
          } // 将 data和 isLoading作为props包装到一个新组件内并返回
        </>
      )
    }
  }
}

// 在App.js中 直接使用  
// ...
const DogShowWithLoader = withLoader(DogShow2, 'https://dog.ceo/api/breeds/image/random');
// ... 
export default withLoader;

注:无论hook 还是 Hoc 都不是一个额外提供的api,只是一种解决方案。都是基于React框架的优化问题的解决方案。

但是张轩大大讲使用HOC还是有些古怪,不妨用自定义的Hooc去实现HOC的功能,进行比较,如下

import React, { useState, useEffect } from 'react';
import axios from 'axios';

const useURLLoader = (url) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  useEffect(() => {
    setLoading(true);
    axios.get(url).then(result => {
      setData(result.data);
      setLoading(false);
    })
  }, [url]);
  return [data, loading];
}

export default useURLLoader;

// 在App.js中
  const CatShowWithHook = () => {
    const [category, setCategory] = useState('1');
    const [data, loading] = useURLLoader(`https://api.thecatapi.com/v1/images/search?limit=1&category_ids=${category}`)
	// 在任何组件中都可以复用useURLLoader hook 非常方便
    return (
      <>
        {loading ? '加载来自hook的猫子'
          : <img src={data && data.length && data[0].url} style={style} />}
        <button onClick={() => setCategory(parseInt(category) + 1)}>刷新猫猫</button>
      </>
    )
  };

相比于HOC,Hook更为轻量,更符合理解认知层面。
Hook可以天然的将一些逻辑重复的代码提取到一个函数当中。

Hook规则

1、只在最顶层使用Hook
2、只在React函数中使用Hook(函数的组件中,自定义Hook中)

electron-is-dev

electron环境下判断环境变量的库。

concurrently + wait-on

react和electron联协的传统方式:
react使用create-react-app 搭建 electron直接安装入devDependencies中
在根目录下创建main.js // electron 主进程相关代码
在package.json中 建script命令 // “dev”: “electron .”
终端1 npm start
终端2 npm run dev

但是这种方式显得有些笨重,需要开两个终端,不方便

使用concurrently库: // 同步运行多命令,同时运行electron和react

// package.json scripts ...
"dev": "concurrently  \"electron .\" \"npm start\""

使用wait-on库 // 等待某一时刻完毕后运行命令,等待3000端口启动完成

// package.json scripts ...
"dev": "concurrently \" wait-on http://localhost:3000 && electron.\" \"npm start\" "

使用cross-env库 // 解决环境变量配置问题,不让react生成选项卡

// package.json scripts ...
"dev": "concurrently \"wait-on http://localhost:3000 && electron .\" \"cross-env BROWSER=none npm start\" "

你可能感兴趣的:(Electron学习之旅1,进程间的通讯,React Hook 自定义Hook,React HOC,electron-is-dev,concurrently + wait-on + cross-env)