此篇接上篇文章: Electron-从零到一搭建-编写基础看框架

这篇文章主要在此基础上来集成ReactMobx, 大家先拉取下上篇demo: https://github.com/spcBackToLife/electron-sprout/tree/release-191017

集成React

主要方式就是将自己写的react组件绑到一个dom元素上。修改render-process中的index.tsx
添加一下React基础依赖:

1
yarn add react react-dom -D

首先,在render-process下新建pages文件夹,并新建pages/index.tsx文件用于放置我们的react页面组件,我们写入一个react组件

1
2
3
4
5
6
import React from 'react';
export const App = () => {
return (<div>
hello
</div>);
}

再在render-process/index.tsx中将react组件绑定到dom上。

1
2
3
4
5
6
7
import ReactDOM from 'react-dom';
import { App } from './pages/index';

ReactDOM.render(
App(),
document.getElementById('root')
);

运行一下,发现无法识别index.tsx里的react组件语法,此时需要装一个@babel/preset-react插件就好:

1
yarn add @babel/preset-react -D

集成mobx

不熟悉mobx的,可以先看看我的另一篇Mobx 基础, 在react中集成mobx分四步:

  • 新建一个stores文件夹,下面共用的store,每个store存储: 状态改变状态的动作(Action)计算值reaction(反馈)等。
  • 使用mobx-react中的Provider包裹react根组件,让你可以把传递下来的store作用在react提供的上下文机制。
  • 在相关组件上使用inject注入想要的状态store,及相关内容,在组件对应文件夹下写相应的store文件。
  • 在具有状态的组件上使用observer, 如果有使用的状态发生变化,则更新该组件。

接下来就是具体demo, demo中也会实验一些特性展示给大家,最后户总结一些东西的使用特点。

  1. render-process/pages下新建mobx-demo文件夹,新建mobx-demo/demo-store.ts
    mobx-demo/demo-store.ts
    先安装下mobx依赖:

    1
    yarn add mobx -D
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    import { observable, action, configure, computed, autorun } from 'mobx';
    // 做一些全局配置,比如: enforceActions,表示此store种更改状态必须使用action
    configure({
    enforceActions: true,
    computedConfigurable: false,
    });

    class DemoStore {
    @observable count = 0; // 定义一个状态变化量,给他@observable检测上。

    @observable test = 1;

    @action // 定义一个改变状态的action
    changeCount = () => {
    console.log('改变count');
    this.count++;
    }

    @action // 定义一个改变状态的action
    changeTest = () => {
    console.log('改变test');
    this.test++;
    }

    @computed get cc() { // 定义计算值:如果相关属性count 变化了,且这个属性被使用了,则会调用此函数计算。
    console.log('属性变化了,执行此函数-cc');
    return this.count + 2;
    }

    @computed get bb() { // 分析测试代码
    console.log('属性变化了,执行此函数-bb');
    return this.count + 2;
    }
    }

    export const demoStore = new DemoStore();

    autorun(() => {
    // 在autorun里用到了哪个变量,如果他变化了,则会自动执行一次autorun
    console.log('demoStore-count:', demoStore.count);
    });

    autorun(() => {
    // 在autorun里用到了哪个变量,如果他变化了,则会自动执行一次autorun
    console.log('demoStore-test:', demoStore.test);
    });
  2. render-process中新建stores文件夹,新建store.ts, 导入所有store

    1
    2
    3
    4
    5
    6
    // 用于定义所有的store
    import { demoStore } from '../pages/mobx-demo/demo-store';

    export const stores = {
    demoStore,
    };

    render-process/pages/index.tsx,react组件入口处使用Provider包裹组件,传入store

    1
    yarn add react-router-dom -D
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import React from 'react';
    import { Provider } from 'mobx-react';
    import { BrowserRouter as Router, Route } from 'react-router-dom';
    import { Demo } from './mobx-demo/index';
    import { stores } from '../stores/stores';

    export function App() {
    return (
    <Provider {...stores}>
    <Router>
    <div>
    <Route path="/" component={Demo} />
    </div>
    </Router>
    </Provider>
    );
    }
  3. 新建组件mobx-demo/index.tsx,并在组件上注入需要的状态store:

    1
    yarn add mobx-react -D

    mobx-demo/index.tsx

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    import React, { PureComponent } from 'react';
    import { inject, observer } from 'mobx-react';

    @inject('demoStore')
    @observer
    export class Demo extends PureComponent<any, any> {
    render() {
    return (
    <div>
    Demo-cc:
    {this.props.demoStore.cc}
    <button onClick={this.props.demoStore.changeCount}>改变count</button>
    <br/>
    Demo-bb:
    {this.props.demoStore.bb}
    <button onClick={this.props.demoStore.changeTest}>改变Test</button>
    </div>
    );
    }
    }

    ps: 如果vscode编辑器出现Property 'props' does not exist on type Home问题,因为ts语法识别问题,我们使用了react,所以安装下type依赖识别语法。我们需要配置下:

    1
    yarn add @types/react -D
  4. 至此,mobx集成完毕,但是运行还是会报错,因为我们使用了装饰器,但是并没有在Babel中处理此语法, 同样还会有ts语法报错,也需要ts的配置,因此,我们需要添加babel配置。

    1
    yarn add @babel/preset-typescript @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties -D

.babelrc 改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "entry",
"modules": false
}
],
["@babel/preset-react"],
["@babel/preset-typescript"]
],
"plugins": [
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-transform-runtime",
["@babel/plugin-proposal-decorators", {"legacy": true}], // 用于装饰器,先 proposal-decorators 再 proposal-class-properties
["@babel/plugin-proposal-class-properties", { "loose": true }] // 用于装饰器
]
}
  1. 我们运行demo: yarn dev 会有如下结论:
    初次加载:

    • 初次加载demoStore时,被@observable的变量被赋值,相应用到改变量的autorun函数也会被执行。
    • 页面上被用到的@computed标记的计算值,会计算一次。

    我们点击改变count的action时候, 发现:

    • changeCount action被执行, cc, bb计算值方法被重新计算
    • 用到count状态的autorun被执行(无论页面是否用到count变量, 只要改变,都会执行),未用到此countautorun未被执行。

    我们先屏蔽掉页面中的bb计算值的使用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import React, { PureComponent } from 'react';
    import { inject, observer } from 'mobx-react';

    @inject('demoStore')
    @observer
    export class Demo extends PureComponent<any, any> {
    render() {
    return (
    <div>
    Demo-cc:
    {this.props.demoStore.cc}
    <button onClick={this.props.demoStore.changeCount}>改变count</button>
    <br/>
    <button onClick={this.props.demoStore.changeTest}>改变Test</button>
    </div>
    );
    }
    }

    我们发现:

    • changeCount action被执行, cc计算值方法被重新计算,与cc同样和count状态相关的bb并没有被执行,因为bb没被使用。

      我们再点击改变Test按钮,发现:

    • 执行了changeTestAction,执行了相关的autorun

    总结:

    • 改变变量的时候,建议使用Action去触发改变,如demo中的changeCount
    • autorun执行的函数中用到的被@observable的变量改变时候则会执行一次此函数,无论变量是否被页面使用。
    • @computed的计算值相关的状态值改变的时候,只有此计算值在页面中使用时才会重新在计算运行一次,否则不再重新计算。

    此篇demo: https://github.com/spcBackToLife/electron-sprout/tree/release-191018
    有问题欢迎加群沟通哦: