mobx-react和umi(乌米)替换redux和react-dom-router方案总结

开始 🔗︎

umi mobx-state-tree umi-plugin-mobx-state-tree

umi初始化项目 🔗︎

yarn create umi

选择app
选择antd <- 如果用了antdesign

umi创建页面 🔗︎

普通路由: <Route path="/home" component={Home} /> 直接创建对应页面: umi g home/index

动态路由: /order-result/:type/:orderId 创建动态页面: umi g orderResult/$type/$orderId/index

umi修改入口页面 🔗︎

在src/pages下建立一个:src/pages/document.ejs 文件

复制模版内容:template/document.ejs到上面文件

然后可以自己定义favicon和其他SEO信息:

<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">

umi修改配置 🔗︎

定义在 .umirc.js或者config/config.js

// ...
  externals: { // 全局变量控制
    wx: 'wx',
    qq: 'qq',
  },
  devServer: {
    contentBase: path.join(__dirname, 'public') // 默认公共目录 本地跑服务时用到
  },
  plugins: [
    // ref: https://umijs.org/plugin/umi-plugin-react.html
    ['umi-plugin-react', {
      antd: true, //是否用antd 
      dva: false,
      title: "国铁商旅", // 默认document.title的值
      dynamicImport: false,
      dll: true,
      routes: {
        exclude: [
          /components\//,
        ],
      },
    }],
    [
      "umi-plugin-mobx-state-tree",//umi-plugin-mobx-state-tree 插件的配置
      {
        exclude: [/^\$/] //这里是以$开头的stores不会被引用
      }
    ]
  ],
  // 全局路径别名
  alias: {
    '@src': path.resolve(__dirname, 'src'),
  },

umi全局mixin样式注入 🔗︎

不用每次在样式文件中import公共的mixin

修改.umirc.js:

  //treeShaking: true,
  chainWebpack(config, {webpack}) {
    // 配置全局mixin
    config.module.rule('mixin-global')
      .test(/\.less$/)
      .use('mixin-with-resources-loader')
      .loader('sass-resources-loader')
      .options({
        resources: [
          path.resolve(__dirname, './src/less/mixin.less')
        ]
      });
  },
 //alias: { }

禁用某些文件的cssModules功能 🔗︎

//...
cssModulesExcludes: [
    '/src/pages/order/index.less',
]
//...

当然你可以完全禁用。具体配置项参看文档。

less全局样式和cssModules样式共存 🔗︎

比如你有一个a.less和a.module.less,两者都需要 因为a.less的class名传递给antdesign的组件,需要重写某些样式:

:global {
    .some-class-name-used {

    }
}

mobx-state-tree管理store 🔗︎

目录结构:

-src 
    -stores (手动创建)
        xxx.js (store的key)

创建一个store 🔗︎

import { types } from "mobx-state-tree";

const userInfoInterface = types.model({
  username: '22',
  password: '123'
});

const XXX = types
  .model('Auth', {
    'type': types.array(types.string, ""),//数组
    'startStationCode': types.maybeNull(types.number),//可以为null
    'startTime': types.optional(types.union(types.number, types.string),0),//允许多个类型
    'userInfo': types.optional(userInfoInterface, {}), //有默认值,允许为undefined。
    'userInfo2': types.maybe(userInfoInterface) //无默认值
  })
  .actions(self => ({
     // 定义的action
     async login(username, password) {

     }
  }));
export default XXX;

全局注册Stores 🔗︎

umi-plugin-mobx-state-tree 约定加载 src/stores 下的所有文件(可通过设置 exclude 排除某些文件)默认开启按需加载

也就是说不用自己创建实例:

const store = Store.create({
    todos: [{
        title: "Get coffee"
    }]
)

并通过Provider的方式注入:

// 伪代码
<Providēr store={store}></Providēr>

React组件注册 🔗︎


// 注解的方式响应式
@observer
class ComponentA extends Component {
    componentDidMount() {
        // 调用store里面的action
        this.props.login()
        // 获取store上的数据
        const { userInfo } = this.props
        // 异步请求后,stores变化。需要主动监听某个数据变化。
        // 比如这里,登陆成功后,跳转到首页
        reaction(
            () => {
                const { userInfo } = this.props
                return userInfo.token
            },
            token => {
                if (token) {
                    this.props.history.push('/home')
                }
            }
        );
        // 另一种写法:
        // autorun(() => {
        // const { userInfo } = this.props
        // if (userInfo.token) {
        // this.props.history.push('/home')
        // }
        // });
    }
}
export default withRouter(inject(({ stores }, ownProps) => ({
  login: stres.xxx.login,//传递stores上的action
  userInfo: stores.xxx.userInfo, //传递stores上的数据
  ...ownProps //传递组件上的数据
}))(ComponentA));
//这种写法某些情况下可能会有问题: }))(observer(ComponentA)));

外部调用stores的action 🔗︎

umi-plugin-mobx-state-tree 会将stores实例注册到window上:

获取store:

// getStore.js
export default () => {
    return window.mobx_app.mobx_stores || {}
}

// a.js
import getStore from 'getStore'
const xxxStore = getStore().xxx
xxxStore.login()

当发布很酷的东西时,请第一时间通知我

订阅电子邮件,以获得我的最新文章。我不会向您发送垃圾邮件。随时取消订阅。