react+ts+mobx+router+antd

安装

npx create-react-app my-app --template typescript
# or
yarn create react-app my-app --template typescript

yarn
# or
npm i
# 添加路由
npm install --save react-router-dom
# 暴露路由
yarn run eject

# 支持less
npm install less-loader less --save

支持less

yarn run eject之后,安装less模块npm install less-loader less --save
在根目录下config\webpack.config.js内找到加入如下代码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0aCQusHd-1585184487761)(https://i.loli.net/2020/03/05/CayIKAHfeWrXLtN.png)]

// style files regexes
const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;

+ const lessRegex = /\.less$/;
+ const lessModuleRegex = /\.module\.less$/;

在 大约350行左右,找到oneOf的数组,在sass模块下,加入如下 less规则。并将importLoaders: 3中的3改为2

 {
              test: lessRegex,
              exclude: lessModuleRegex,
              use: getStyleLoaders(
                {
                  // importLoaders: 3,
                  importLoaders: 2,
                  sourceMap: isEnvProduction && shouldUseSourceMap,
                },
                'less-loader'
              ),
              sideEffects: true,
            },
            {
              test: lessModuleRegex,
              use: getStyleLoaders(
                {
                  // importLoaders: 3,
                  importLoaders: 2,
                  sourceMap: isEnvProduction && shouldUseSourceMap,
                  modules: {
                    getLocalIdent: getCSSModuleLocalIdent,
                  },
                },
                'less-loader'
              ),
            },

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KuhNto5t-1585184487771)(https://i.loli.net/2020/03/05/RSLznh92xbQGsqk.png)]

安装 antd

# 安装antd
npm install antd --save
# 安装 按需加载 
npm install babel-plugin-import --save-dev

package.json添加配置

  "babel": {
    "presets": [
      "react-app"
    ],
+    "plugins": [
+      ["import", {
+        "libraryName": "antd",
+        "libraryDirectory": "es",
+        "style": "css" 
+      }]
+    ]
  }
}

按需加载

npm install babel-plugin-import --save-dev

router 页面布局

安装路由

npm i react-router-dom
npm install --save-dev  @types/react @types/react-dom @types/react-router-dom
  • react-router-dom
    做成后台公共组件的形式,需要把 登录页面 和 错误页面暴露出去;这时候遇到问题,两种解决方案。
  1. 将404、500等报错页面放到公共组件下面。
  2. 每个路由包一层layout,单独放 login 和 404、500等报错页面。

使用withRouter 报错

一个资深大神给的建议:说 mobx 和 react-router-dom 这两个包不兼容的时候,使用any;就可以了。如下:

@(withRouter as any)

antd 4.x 版本icon 变成按需引入

antd 4.x 版本icon 变成按需引入,icon不能一次全部加载进去,下面 是解决方案。

安装 mobx


使用Mobx作为app状态管理方案

记得安装 MobX Developer Tools

mobx 开发 谷歌插件

npm install --save mobx mobx-react
# 安装 装饰器 将 class或者object 转成 ES5
npm install --save-dev @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators

npm install babel-plugin-transform-class-properties -D

npm install --save-dev babel-plugin-transform-decorators-legacy

并在tsconfig.json中加入一行配置来使ts支持装饰器语法:

{
  "compilerOptions": {
    "experimentalDecorators": true
  }
}

Mobx 用法示例

  1. src下建立stores文件夹。并依次建立detail.tsindex.ts
reatc-example
├── src
│   ├── stores
│   │   │── detail.ts
│   │   └── index.ts
│   └── index.tsx
├── config
│   └── webpack.config.js
└── package.json
  1. detail.ts文件
//detail.ts
import { action, observable } from 'mobx'

interface Cat {
    name: string;
    age?: number | string;
    color?: string;
}
export default class DetailStore {

    @observable name: string = 'Clint'
    @observable arr: Cat[] = []

    constructor(initialState: any = { name: 'detail-store', arr: [{ name: 'Tom', color: 'red' },{ name: 'Jerry',age:'3', color: 'blue' }] }) {
        this.name = initialState.name;
        this.arr = initialState.arr;
    }

    @action
    public setName = (name: string) => {
        this.name = name
    }
    public changeArray = (item: Cat) => {
        this.arr.push(item)
    }
}
  1. index.ts文件,store的初始化
//index.ts
import HomeStore from './home'
import DetailStore from './detail'

export default {
    homeStore: new HomeStore(),
    detailStore: new DetailStore(),
}
  1. 配置Provider 在src/index.tsx
// src/index.tsx

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'mobx-react'

import Router from './router/router';
// import './index.css';
import stores from './stores/index';
// import * as serviceWorker from './serviceWorker';

ReactDOM.render(
    <Provider {...stores}>
        <Router />
    </Provider>,
    document.getElementById('root'));
  1. 使用store
    注意这里 在react 中,会用到装饰器,而装饰器写法只能在 class 类组件中使用。而 函数式组件 只能 使用嵌套的方式。
    一、 第一种 class 组件中。
// home.tsx
import React, { Component } from 'react';
import { Link } from "react-router-dom";
import { Button } from 'antd';
import { observer, inject } from 'mobx-react'
import homeStore from '../../stores/home'
import './home.less';
type IProps = {
    homeStore: homeStore
    errors?: string
}
@inject('homeStore')
@observer
class Home extends Component<IProps> {
    private clickHandler = (): void => {
        // const { homeStore } = this.props;
        // homeStore.setName("Bob");
        const {setName}=this.props.homeStore
        setName("Bob666")
    }

    render() {
        return (
            <div className="home">
                <h1 className='home-item'>Home</h1>
                <h2>{this.props.homeStore.name}</h2>
                <Link to='/detail'>详情</Link>
                <Link to='/login'>登录</Link>
                <Button onClick={this.clickHandler} type="primary">改名字</Button>
            </div>
        )
    }
};
export default Home;

【注意】如果 在store 里面,声明的 action 函数,不是用的 => 函数,可能出现this指向问题。如下面的例子:

/**
 * 第一种
*/
// store 中
  @action
  public setName(name: string) {
    // 没有使用 箭头函数
    this.name = name
  }
  // 使用
  private clickHandler = (): void => {
        const {setName}=this.props.homeStore
        setName("Bob666")
        // 这时候 this 指向 undefined
        // 所以 报错,可以改写成下面方式,即可解决
        // const { homeStore } = this.props;
        // homeStore.setName("Bob");
  }
/**
 * 第二种
*/
  @action
  public setName = (name: string) => {
    // 箭头函数
    this.name = name
  }
  //使用
    private clickHandler = (): void => {
        const {setName}=this.props.homeStore
        setName("Bob666")
        // 这时候 this 指向 store
        // 成功
  }

二、 第二种 函数 组件中

import React from 'react';
import { Link } from "react-router-dom";
import { observer, inject } from 'mobx-react'
type IProps = {
    [key: string]: any
}
const Detail: React.FC<{}> = inject('detailStore')(observer((props: IProps) => (
    <div className="App">
        <h3>Detail</h3>
        <h6>{props.detailStore.name}</h6>
        <ul>
            {props.detailStore.arr.map((v: any) => <li key={v.name}>{v.name}</li>)}
        </ul>
        <Link to='/home'>首页</Link>
        <Link to='/lll'>空页面</Link>
    </div>
)));

export default Detail;

fetch && axios

  1. 安装 js-cookie
npm i js-cookie @types/js-cookie --save
  1. 使用 fetch
  • Fetch
    utils/request-fetch.ts文件夹下

打包

npm run build

但是 会生成.map文件;上线的时候我们需要去掉这个文件。
config/webpack.config.js内 第33行

// Source maps are resource heavy and can cause out of memory issue for large source files.
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';

直接将改为

const shouldUseSourceMap = 'false';

即可。
第二种办法,由上面的信息可知,.map文件是由回家变量process.env.GENERATE_SOURCEMAP控制的。所以由于打包的时候执行的脚本文件是scripts/build.js,所在在scripts/build.js内添加如下代码即可。

// 打包禁止生成 .map 文件
process.env.GENERATE_SOURCEMAP = 'false';

报错

  1. yarn or npm
Attempted import error: 'Route' is not exported from 'react-router-dom'.
  1. pages/login/components/LoginForm.tsx中引入store会报错。
  1. Instance created byuseFormis not connect to any Form element. Forget to passformprop?报错
发布了84 篇原创文章 · 获赞 75 · 访问量 34万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览