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(); // 开启调试工具
});
// 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、主进程回复渲染进程
});
// renderer.js 渲染进程中
const { BrowserWindow } = require('electron').remote;
// 注:remote其实是electron内部实现的消息通讯,方便我们开发者使用
使用Emitter事件
菜单项回调,需要主进程,创建第二个渲染进程。
main.js 接收emit事件
Hook: 无需修改组件结构情况下,复用状态逻辑。
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;
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一个函数,会在第二次渲染触发,可以用于清除监听事件。
事件添加在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;
先看个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可以天然的将一些逻辑重复的代码提取到一个函数当中。
1、只在最顶层使用Hook
2、只在React函数中使用Hook(函数的组件中,自定义Hook中)
electron环境下判断环境变量的库。
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\" "