react+typescript+umi+dva+antd

背景

  • React
    前端三大框架之一。
  • typescript
    javascript的超集
  • Dva
    由阿里架构师 sorrycc 带领 team 完成的一套前端框架,在作者的 github 里是这么描述它的:”dva 是 react 和 redux 的最佳实践”。
  • Antd
    是阿里的一套开箱即用的中台前端/设计解决方案,UI框架。
  • Umi
    一套可插拔的企业级 react 应用框架,同样由dva作者 sorrycc 完成。他在Umi中引入了 UI 工具 antd,打包工具 roadhog,路由 react-router和状态管理器 dva,做到了可插拔机制。

创建一个umi应用

  1. 先安装node,再创建一个项目文件夹,通过脚手架创建umi项目

    npx @umijs/create-umi-app
    

    在这里插入图片描述
    在这里插入图片描述

  2. 安装依赖

    npm i 
    
  3. 运行项目

    npm run start
    

    在这里插入图片描述

umi应用的路由

配置路由

在配置文件.umirc.ts中通过 routes 进行配置,格式为路由信息的数组。

routes: [
  { path: '/', component: '@/pages/Index' },
  { path: '/User', component: '@/pages/User' },
],

在这里插入图片描述

路由配置工程化

为了让代码更工程化,我们可以将路由配置单独拆分成一个文件
router.tsx

const router: any = [
  { path: '/', component: '@/pages/Index' },
  { path: '/User', component: '@/pages/User' },
]

export default router;

.umirc.ts

import { defineConfig } from 'umi';
import router from '@/router/router'; // 引入路由配置文件

export default defineConfig({
  nodeModulesTransform: {
    type: 'none',
  },
  routes: router,
});

在这里插入图片描述

约定式路由

除配置式路由外,Umi 也支持约定式路由。约定式路由也叫文件路由,就是不需要手写配置,文件系统即路由,通过目录和文件及其命名分析出路由配置。
在这里插入图片描述
备注:约定式路由要先注释.umirc.ts里的routes配置

路由跳转

import { history } from 'umi';
// 跳转到指定路由
history.push('/list');
// 带参数跳转到指定路由
history.push('/list?a=b');
history.push({
  pathname: '/list',
  query: {
    a: 'b',
  },
});
// 跳转到上一个路由
history.goBack();

示例
Index.tsx

import React, { Component } from 'react'
import { history } from 'umi';
import styles from '@/assets/Style/Index.less'; // css module

export default class Index extends Component {
  // 路由跳转不带参数
  toLogin() {
    history.push('/login');
  }
  // 路由跳转带参数
  toLoginWithParameter() {
    history.push({
      pathname: '/login',
      query: {
        a: 'b',
      },
    })
  }
  render() {
    return (
      <div>
      	<div className={styles.title}>首页</div>
        <div onClick={this.toLogin}>跳转不带参数</div>
        <div onClick={this.toLoginWithParameter}>跳转带参数</div>
      </div>
    )
  }
}


User.tsx

import React, { Component } from 'react'
export default class User extends Component {
  constructor(props: any) {
    super(props);
    console.log(props.location.query) // 打印路由参数
  }
  render() {
    return (
      <div>
        <h1 className={styles.title}>User</h1>
      </div>
    )
  }
}

安装插件集@umijs/preset-react

@umijs/preset-react是包含antd,dva等一系列插件的插件集,由于使用指令npx @umijs/create-umi-app创建的项目会自动添加此插件,所以之后不需要再安装@umijs/preset-react插件集包含的插件,否则启动项目的时候会报错
在这里插入图片描述

umi+antd

安装了插件集@umijs/preset-react之后,无需再做任何配置,直接可以按需加载antd并在组件中使用

import React, { Component } from 'react'
import { history } from 'umi';
import { Button } from 'antd'; // 引入antd组件
import styles from '@/assets/Style/Index.less'; // css module

export default class Index extends Component {
  // 路由跳转不带参数
  toUser() {
    history.push('/User');
  }
  // 路由跳转带参数
  toUserWithParameter() {
    history.push({
      pathname: '/User',
      query: {
        a: 'b',
      },
    })
  }
  render() {
    return (
      <div>
      	<div className={styles.title}>首页</div>
        <Button type="primary" onClick={this.toUser}>跳转不带参数</Button>
        <Button type="primary" onClick={this.toUserWithParameter}>跳转带参数</Button>
      </div>
    )
  }
}


在这里插入图片描述

umi+dva

安装了插件集@umijs/preset-react之后,无需再做任何配置,直接可以使用dva
在这里插入图片描述

  1. 创建models目录以及model文件userInfo.tsx

    import { Effect, ImmerReducer, Reducer, Subscription } from 'umi';
    export interface UserInfoModelState {
      name: string;
      age: number;
    }
    export interface UserInfoModelType {
      namespace: 'userInfo';
      state: UserInfoModelState;
      effects: {
        query: Effect;
      };
      reducers: {
        save: Reducer<UserInfoModelState>;
        changeName: Reducer<UserInfoModelState>;
        // 启用 immer 之后
        // save: ImmerReducer<UserInfoModelState>;
      };
      subscriptions: { setup: Subscription };
    }
    const UserInfoModel: UserInfoModelType = {
      namespace: 'userInfo',
      state: {
        name: '张三',
        age: 20,
      },
      effects: {
        *query({ payload }, { call, put }) {
        },
      },
      reducers: {
        save(state, action) {
          return {
            ...state,
            ...action.payload,
          };
        },
        changeName(state, action) {
          return {
            ...state,
            ...action.payload,
          };
        },
        // 启用 immer 之后
        // save(state, action) {
        //   state.name = action.payload;
        // },
      },
      subscriptions: {
        setup({ dispatch, history }) {
          return history.listen(({ pathname }) => {
            if (pathname === '/') {
              dispatch({
                type: 'query',
              })
            }
          });
        }
      }
    };
    export default UserInfoModel;
    
  2. 组件中使用

  • class组件中使用

    import React, { Component } from 'react'
    import { connect, UserInfoModelState, Loading } from 'umi';
    
    const connect1: any = connect;
    
    @connect1(({ userInfo, loading }: { userInfo: UserInfoModelState; loading: Loading }) => ({
      userInfo,
      // dva-loading可以自动处理loading状态
      loading: loading.models.index,
    }))
    export default class User extends Component<any, any> {
      constructor(props: any) {
        super(props);
        console.log(props);
        this.state = {
          username: props.userInfo.name
        }
      }
      // 调用userInfo模块的reducers里的changeName方法
      private changeName = () => {
        const { dispatch } = this.props;
        dispatch({
            type: 'userInfo/changeName',
            payload:{
              name: '李四'
            }
        })
      }
      render() {
        return (
          <div>
            <div onClick={this.changeName}>更改用户名</div>
            <div className="title">用户名{this.props.userInfo.name}</div>
          </div>
        )
      }
    }
    
  • 函数式组件中使用

    import React, { FC } from 'react';
    import { UserInfoModelState, ConnectRC, Loading, connect } from 'umi';
    interface PageProps {
      userInfo: UserInfoModelState;
      loading: boolean;
    }
    
    const IndexPage: FC<PageProps> = (props) => {
      const handleClick = () => {
        const { dispatch } : any = props;
        dispatch({
          type: 'userInfo/changeName',
          payload:{
            name: '李四'
          }
        })
      }
      return (
        <div>
          <div onClick={handleClick}>更改用户名</div>
          <div className="title">用户名{props.userInfo.name}</div>
        </div>
      )
    };
    export default connect(({ userInfo, loading }: { userInfo: UserInfoModelState; loading: Loading }) => ({
      userInfo,
      loading: loading.models.index,
    }))(IndexPage);
    

    在这里插入图片描述

  • 项目目录
    在这里插入图片描述

主要文章参考
https://www.icode9.com/content-4-652359.html
https://www.cnblogs.com/llcdbk/p/13029996.html
https://www.cnblogs.com/crazycode2/p/8593143.html
https://www.jianshu.com/p/86bd9fc0a219
https://segmentfault.com/q/1010000014835057
https://blog.csdn.net/YMX2020/article/details/106674097
https://blog.csdn.net/SCU_Cindy/article/details/82432971

初次尝试,摸坑永不止步,还有以下文章也参考了一下,拓展思路
https://www.cnblogs.com/jiawei-Wang/p/11400848.html
https://segmentfault.com/a/1190000021272819?utm_source=tag-newest
https://zhuanlan.zhihu.com/p/69200639
https://www.yuque.com/umijs/umi/dvamodels
https://www.codercto.com/a/25627.html
https://blog.csdn.net/deletGlobal/article/details/106183217
https://blog.csdn.net/YMX2020/article/details/106674097
https://zhuanlan.zhihu.com/p/92617879
http://www.caotama.com/294655.html
https://www.cnblogs.com/winfred/p/8216650.html
https://www.jianshu.com/p/21f8ed30e761
https://www.cnblogs.com/axel10/p/8503782.html
https://www.jianshu.com/p/81a5d4371f81
https://blog.csdn.net/sllailcp/article/details/89384328
https://www.cnblogs.com/lucas27/p/9292058.html
https://www.jianshu.com/p/c1a4166d9eda
https://blog.csdn.net/Leonardo_Zhu/article/details/96482371
https://www.jianshu.com/p/21f8ed30e761

  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值