阅读 50

Electron+react+mobx

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

这篇文章主要在此基础上来集成ReactMobx, 大家先拉取下上篇demo: github.com/spcBackToLi…

集成React

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

yarn add react react-dom -D
复制代码

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

import React from 'react';
export const App = () => {
  return (<div>
    hello
  </div>);
}
复制代码

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

import ReactDOM from 'react-dom';
import { App } from './pages/index';

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

复制代码

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

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依赖:
  yarn add mobx -D
复制代码
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);
});

复制代码
  1. render-process中新建stores文件夹,新建store.ts, 导入所有store
// 用于定义所有的store
import { demoStore } from '../pages/mobx-demo/demo-store';

export const stores = {
  demoStore,
};

复制代码

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

  yarn add react-router-dom -D
复制代码
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>
  );
}
复制代码
  1. 新建组件mobx-demo/index.tsx,并在组件上注入需要的状态store:
yarn add mobx-react -D
复制代码

mobx-demo/index.tsx

  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依赖识别语法。我们需要配置下:

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

.babelrc 改为:

  {
    "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计算值的使用: ```javascript 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`按钮,发现:
- 执行了`changeTest`Action,执行了相关的`autorun`
复制代码

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

此篇demo: github.com/spcBackToLi… 有问题欢迎加群沟通哦:

关注下面的标签,发现更多相似文章
评论