zoukankan      html  css  js  c++  java
  • 《umi+ts+antd Pro 珠峰课程【1】》

    https://www.bilibili.com/video/BV1JJ411q7iw

    umi+ts+antd Pro 珠峰课程

     

     

     

    npm install -g cnpm --registry=https://registry.npm.taobao.org

    cnpm install -g yarn

    yarn create umi 

     

    git init 

    npm i

     扩展 window,加了一些属性

    umi+dva 项目快速上手指南

    在 react 项目中,使用 react+umi+dva+antd 这一阿里系列技术栈的人越来越多,本文就来分享一下 umi 项目的上手教程。在 react 项目中,使用 react+umi+dva+antd 这一阿里系列技术栈的人越来越多,本文就来分享一下 umi 项目的上手教程。

    构建项目

    node 环境

    node 版本 >= 8.0.0

    全局安装 umi

    npm install -g umi 

    建议使用 yarn 安装

    // 全局安装yarn
    npm install -g yarn
    
    // 使用yarn安装umi
    yarn global add umi

    构建 umi 项目

    mkdir myapp && cd myapp
    yarn create umi

    详细构建请参考 umi 官方项目构建

    目录结构

    ├── config/
        ├── config.js                  // umi 配置,同 .umirc.js,二选一
    ├── dist/                          // 默认的 build 输出目录
    ├── mock/                          // mock 文件所在目录,基于 express
    ├── public/                        // 全局相对路径文件
    └── src/                           // 源码目录,可选
        ├── assets/                    // 静态文件
        ├── components/                // 全局共用组件
        ├── layouts/index.js           // 全局入口文件
        ├── models/                    // 全局models文件,存放全局共用数据store
        ├── pages/                     // 页面目录,业务组件
            ├── .umi/                  // dev 临时目录,需添加到 .gitignore
            ├── .umi-production/       // build 临时目录,会自动删除
            ├── index/                 // 首页模块
            ├── manager/               // 管理端模块
                ├── components/        // 管理端-局部公共组件
                ├── models/            // 管理端-局部models,存放manager的store
                ├── services/          // 管理端-局部services,存放manager的接口
                ├── index.js           // 业务组件index
                ├── page.js            // 业务组件page
                ├── _layout.js         // 局部入口文件
            ├── 404.js                 // 404 页面
        ├── services/                  // 全局services文件,存放全局公共接口
        ├── utils/                     // 全局工具类
        ├── global.css                 // 约定的全局样式文件,自动引入,也可以用 global.less
        ├── global.js                  // 约定的全局Js文件,自动引入,可以在这里加入 polyfill
        ├── app.js                     // 运行时配置文件
    ├── .umirc.js                      // umi 配置,同 config/config.js,二选一
    ├── .env                           // 环境变量
    └── package.json

    配置文件

    umi 允许在 .umirc.js 或 config/config.js (二选一,.umirc.js 优先)中进行配置,支持 ES6 语法。本文使用 config/config.js

    export default {
      base: '/web/',  //部署到非根目录时才需配置
      targets: { //配置浏览器最低版本,比如兼容ie11
       ie: 11
      },
      hash: true,  //开启打包文件的hash值后缀
      treeShaking: true, //去除那些引用的但却没有使用的代码
      plugins: [
        [
          'umi-plugin-react',
          {
            antd: true, //启用后自动配置 babel-plugin-import,实现antd按需加载
            dynamicImport: { //实现路由级的动态加载
              webpackChunkName: true //实现有意义的异步文件名
            },
            dva: {
              dynamicImport: true, //是否启用按需加载
              hmr: true //是否启用 dva 的 热更新
            },
            //通过 webpack 的 dll 插件预打包一份 dll 文件来达到二次启动提速的目的
            dll: {
              exclude: [],
              include: ['dva', 'dva/router', 'dva/saga', 'dva/fetch', 'antd/es']
            },
            //约定式路由时才需引用,用于忽略指定文件夹中自动生成的路由
            routes: {
              exclude: [
                /components//,
                /model.(j|t)sx?$/,
                /components.(j|t)sx?$/,
                /service.(j|t)sx?$/,
                /models//,
                /services//
              ],
            },
          }
        ]
      ],
      //配置式路由时,路由文件由此引用(往下会讲到)
      routes: routes,
      //代理请求
      proxy: {
        "/api": {
          "target": "http://jsonplaceholder.typicode.com/",
          "changeOrigin": true,
          "pathRewrite": { "^/api" : "" }
        }
      },
      alias: {'@': resolve(__dirname, '../src'),} //别名,umirc.js为'src'
    };

    pages

    + pages
      + manager
        + components/
        + models/
        + services/
        - index.js
        - _layout.js

    业务目录中,标配局部公用组件 components,局部共用数据 models,局部共用接口 services,_layout.js 入口文件需要则引入。

    路由

    1. 约定式路由

    1.1 umi 约定,在 pages 目录下的. js/.jsx 会自动生成路由,除开在配置文件 plugins/routes 中被 exclude 的目录或文件,文件的路径即路由。 1.2 src/layout / 为全局 layout,默认全局入口文件,配置式路由下无效。pages / 下任何文件下的_layout.js 即当前文件夹路由下的入口文件,必须先经过_layout.js 才能进入当前文件夹路由

    2. 配置式路由

    在配置文件 .umirc.(ts|js) 或者 config/config.(ts|js) 中引入:

    export default {
      routes: [
        {
          path: '/',
          component: '../layouts/index',
          routes: [
            { path: '/user', redirect: '/user/login' },//redirect,避免只渲染_layout.js
            { path: '/user/login', component: './user/login' },
            {
              path: '/manager', component: '../pages/management/_layout.js',
              routes: [
                { path: '/manager/system', component: '../pages/management/manager/system', Routes: ['./routes/PrivateRoute.js'] }
            }
          ],
        },
      ],
    };

    3. 权限路由

    路由通过 Routes 属性来实现权限路由, 如上文:/manager/system 路由。创建一个./routes/PrivateRoute.js 权限文件,props 里会传入 / manager/system 的路由信息。

    export default (props) => {
      return (
        <div>
          <div>PrivateRoute (routes/PrivateRoute.js)</div>
          { props.children }
        </div>
      );
    }

    4. 跳转路由

    link 方式

    import Link from 'umi/link';
      <Link to="/list">Go to list page</Link>

    router 方式

    import router from 'umi/router';
      router.push({
        pathname: '/list',
        query: {
          a: 'b',
        },
      });

    models 层

    models/index.js,不能空文件。由于 umi/dva 是基于 redux,redux-saga 的数据流方案,dva 的 connect 即 redux 的 connect,dva 的 model 即 redux-saga 简化版,更易用。

    import * as services from '../services';
    {
      namespace: 'system',   //models命名空间,需全局唯一
      state: {               //models存储的数据store
        dataList: []
      },                     
      reducers: {
        save(state, { payload }) {          //更新store,用新数据合并state的旧数据
          return { ...state, ...payload };
        }
      },
      effects: {
        * testFunc({ payload: params }, { call, put, select }) {   //dispatch请求的方法
          const { dataList } = yield select(state => state.system); //获取models中的state
          const { data } = yield call(services.testFunc, params);  //call,请求services里面的接口以及传参,可继续往后面加参数,跟JavaScript的call一样
          if (data && data.code == 0) {
            const data_ = data.data.content;
            yield put({ //put,必须发出action save,此action被reducer监听,从而达到更新state数据的目的
              type: 'save',                                        
              payload: {
                dataList: data_ || []
              }
            });
            return data_;   //返回response,可选
          }                                                        
        },
      },
      subscriptions: {      //订阅,在app.start()即启动项目时被执行
        setup({ dispatch, history }) {
          return history.listen(({ pathname, query }) => {
            // 进入 '/manager/system' 路由,会发起一个名叫 'save' 的 effect
            if (pathname === '/manager/system') {
                        //do sth... dispatch({ type: 'save', payload: query });
                    }
          })
        }
      }
    }

    注:call 会阻塞,在 call 方法调用结束之前,call 方法之后的语句是无法执行的,使得以同步的方式执行异步,如需无阻塞,则要引入 fork,用 yield fork 代替 yield call。

    services 层

    请求后台接口的方法,返回一个 promise 对象。

    import request from '@utils/request';
    
    export function rightSave(values) {
      return request(`/authirty/right/save`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(values)
      });
    }

    components 层

    dispatch

    与 effect 中的 put 方法相似,必须触发 action。 在 model 的 subscription 参数中使用。 在组件中,由 connect 过的组件中,组件的 props 中才可以获取到 dispatch。

    import { connect } from 'dva'; 
    export default connect()(System);
    • 接口请求 方式一 (推荐): 使用 dispatch 调用 models 里面 effects/reducer 声明的方法,

    this.props.dispatch({
      type: 'system/testFunc',   //type,命名空间/effects方法名
      payload: params,           //payload,参数
    }).then(res => {})
    
    //直接赋值更新state
    this.props.dispatch({
      type: 'system/save',  //type,命名空间/reducer方法名
      payload: {
        rightDetail: {a:1}
      },                    //payload,参数
    }).then(res => {})
    
    //请求全局model
    this.props.dispatch({
      type: 'global/getOrganizationList',  //全局namespace/全局effects方法名
      payload: params,                     //payload,参数
    }).then(res => {})

    方式二:dispatch 带 callback 回调函数作为第三个参数

    //组件中
    this.props.dispatch({
      type: 'system/testFunc',
      payload: params,
      callback: (res) => {
        if (!!res) {
          //do sth
        }
      }
    });
    
    //model中
    *testFunc({ payload, callback }, { call, put }){
      const { data } = yield call(services.rightSave, payload);
      if (data && data.code == 0) {
        !!callback && && callback(data);
      }
    }

    方式三 (少用):如果组件中不需要用到 model 存 store 时,直接引入 services 请求接口

    //组件中
    //使用new promise请求接口,service返回promise函数,待接口异步请求完才执行.then
    import * as service from '../services'; 
    new Promise((resolve) => {
      const ret = service.rightSave(param);
      resolve(ret);
    }).then((ret) => {
      if (ret && ret.code == 200) {
        //do sth
      }
    });
    
    // 或者
    // 现在的ajax框架返回的就是一个promise的话,可以直接方法名跟上.then()即可
    import { rightSave } from '../services';
    rightSave().then(res => {
      let data = res.data;
      if (data && data.code == 200) {
        //do sth
      }
    });

    connect

    方式一:mapStateToProps,class 继承组件和函数组件都能用这种

    接口请求完后,组件中引入 connect,获取 models 的数据放入当前组件 props 中

    import { connect } from 'dva'; 
    function mapStateToProps(state) { //state是项目所有的models
      const { selectList } = state.system; //获取namespace命名空间为system的models数据state
      const { organizationList } = state.global; //全局获取namespace命名空间为global的models数据state
      return {
        selectList,
        organizationList
      };
    }
    export default connect(mapStateToProps)(System);   //connect组件
    //或者直接解构
    export default connect(({ system, global: { organizationList } }) => ({ ...system, organizationList }))(System);

    方式二:es6 注解方式引入,只能用于 class 继承组件

    @connect(({ system, global: {organizationList} }) => ({ 
      ...system,
      organizationList
    }))
    class System extends React.Component{render(){return {<></>}}}

    withRouter

    withRouter 的作用:未经路由跳转的组件,如子组件想拿到路由的相关信息 location、history、match 等时可用,经路由跳转的页面则默认已有路由信息。 FAQ: 1. url 变化了,但页面组件不刷新,是什么原因? layouts/index.js 里如果用了 connect 传数据,需要用 umi/withRouter 高阶一下

    import withRouter from 'umi/withRouter';
    export default withRouter(connect(mapStateToProps)(LayoutComponent));
    1. 全局 layout 使用 connect 后路由切换后没有刷新? 需用 withRouter 包一下导出的 react 组件,注意顺序。
    import withRouter from 'umi/withRouter';
    export default withRouter(connect()(Layout));

    mock

    export default {
      // 支持值为 Object 和 Array
      'GET /api/users': { users: [1, 2] },
      // 支持自定义函数,API 参考 express@4
      'POST /api/users/create': (req, res) => { res.end('OK'); },
    }

    如请求接口 / api/list,数据返回 {users: [1, 2] }

    数据流程

    最后给大家总结一下 dva 的数据流向: * View 层 dispatch 操作 action –> 触发 models 层 effect 中相应方法 –> 触发 call 发起 services 层请求,获取接口数据 –> 触发 put 发起 reducer 处理相应的 action 更新数据 –> 更新 model 层中 state –> 触发 view 层的 render 方法进行重新渲染 –> 页面更新

    附上数据流向图

    参考文档

    umi 文档:https://umijs.org/zh/guide/ dva 文档:https://dvajs.com/guide/

    ps: 如有纰漏,请留言更正!

    构建项目

    node 环境

    node 版本 >= 8.0.0

    全局安装 umi

    npm install -g umi 

    建议使用 yarn 安装

    // 全局安装yarn
    npm install -g yarn
    
    // 使用yarn安装umi
    yarn global add umi

    构建 umi 项目

    mkdir myapp && cd myapp
    yarn create umi

    详细构建请参考 umi 官方项目构建

    目录结构

    ├── config/
        ├── config.js                  // umi 配置,同 .umirc.js,二选一
    ├── dist/                          // 默认的 build 输出目录
    ├── mock/                          // mock 文件所在目录,基于 express
    ├── public/                        // 全局相对路径文件
    └── src/                           // 源码目录,可选
        ├── assets/                    // 静态文件
        ├── components/                // 全局共用组件
        ├── layouts/index.js           // 全局入口文件
        ├── models/                    // 全局models文件,存放全局共用数据store
        ├── pages/                     // 页面目录,业务组件
            ├── .umi/                  // dev 临时目录,需添加到 .gitignore
            ├── .umi-production/       // build 临时目录,会自动删除
            ├── index/                 // 首页模块
            ├── manager/               // 管理端模块
                ├── components/        // 管理端-局部公共组件
                ├── models/            // 管理端-局部models,存放manager的store
                ├── services/          // 管理端-局部services,存放manager的接口
                ├── index.js           // 业务组件index
                ├── page.js            // 业务组件page
                ├── _layout.js         // 局部入口文件
            ├── 404.js                 // 404 页面
        ├── services/                  // 全局services文件,存放全局公共接口
        ├── utils/                     // 全局工具类
        ├── global.css                 // 约定的全局样式文件,自动引入,也可以用 global.less
        ├── global.js                  // 约定的全局Js文件,自动引入,可以在这里加入 polyfill
        ├── app.js                     // 运行时配置文件
    ├── .umirc.js                      // umi 配置,同 config/config.js,二选一
    ├── .env                           // 环境变量
    └── package.json

    配置文件

    umi 允许在 .umirc.js 或 config/config.js (二选一,.umirc.js 优先)中进行配置,支持 ES6 语法。本文使用 config/config.js

    export default {
      base: '/web/',  //部署到非根目录时才需配置
      targets: { //配置浏览器最低版本,比如兼容ie11
       ie: 11
      },
      hash: true,  //开启打包文件的hash值后缀
      treeShaking: true, //去除那些引用的但却没有使用的代码
      plugins: [
        [
          'umi-plugin-react',
          {
            antd: true, //启用后自动配置 babel-plugin-import,实现antd按需加载
            dynamicImport: { //实现路由级的动态加载
              webpackChunkName: true //实现有意义的异步文件名
            },
            dva: {
              dynamicImport: true, //是否启用按需加载
              hmr: true //是否启用 dva 的 热更新
            },
            //通过 webpack 的 dll 插件预打包一份 dll 文件来达到二次启动提速的目的
            dll: {
              exclude: [],
              include: ['dva', 'dva/router', 'dva/saga', 'dva/fetch', 'antd/es']
            },
            //约定式路由时才需引用,用于忽略指定文件夹中自动生成的路由
            routes: {
              exclude: [
                /components//,
                /model.(j|t)sx?$/,
                /components.(j|t)sx?$/,
                /service.(j|t)sx?$/,
                /models//,
                /services//
              ],
            },
          }
        ]
      ],
      //配置式路由时,路由文件由此引用(往下会讲到)
      routes: routes,
      //代理请求
      proxy: {
        "/api": {
          "target": "http://jsonplaceholder.typicode.com/",
          "changeOrigin": true,
          "pathRewrite": { "^/api" : "" }
        }
      },
      alias: {'@': resolve(__dirname, '../src'),} //别名,umirc.js为'src'
    };

    pages

    + pages
      + manager
        + components/
        + models/
        + services/
        - index.js
        - _layout.js

    业务目录中,标配局部公用组件 components,局部共用数据 models,局部共用接口 services,_layout.js 入口文件需要则引入。

    路由

    1. 约定式路由

    1.1 umi 约定,在 pages 目录下的. js/.jsx 会自动生成路由,除开在配置文件 plugins/routes 中被 exclude 的目录或文件,文件的路径即路由。 1.2 src/layout / 为全局 layout,默认全局入口文件,配置式路由下无效。pages / 下任何文件下的_layout.js 即当前文件夹路由下的入口文件,必须先经过_layout.js 才能进入当前文件夹路由

    2. 配置式路由

    在配置文件 .umirc.(ts|js) 或者 config/config.(ts|js) 中引入:

    export default {
      routes: [
        {
          path: '/',
          component: '../layouts/index',
          routes: [
            { path: '/user', redirect: '/user/login' },//redirect,避免只渲染_layout.js
            { path: '/user/login', component: './user/login' },
            {
              path: '/manager', component: '../pages/management/_layout.js',
              routes: [
                { path: '/manager/system', component: '../pages/management/manager/system', Routes: ['./routes/PrivateRoute.js'] }
            }
          ],
        },
      ],
    };

    3. 权限路由

    路由通过 Routes 属性来实现权限路由, 如上文:/manager/system 路由。创建一个./routes/PrivateRoute.js 权限文件,props 里会传入 / manager/system 的路由信息。

    export default (props) => {
      return (
        <div>
          <div>PrivateRoute (routes/PrivateRoute.js)</div>
          { props.children }
        </div>
      );
    }

    4. 跳转路由

    link 方式

    import Link from 'umi/link';
      <Link to="/list">Go to list page</Link>

    router 方式

    import router from 'umi/router';
      router.push({
        pathname: '/list',
        query: {
          a: 'b',
        },
      });

    models 层

    models/index.js,不能空文件。由于 umi/dva 是基于 redux,redux-saga 的数据流方案,dva 的 connect 即 redux 的 connect,dva 的 model 即 redux-saga 简化版,更易用。

    import * as services from '../services';
    {
      namespace: 'system',                             //models命名空间,需全局唯一
      state: {
        dataList: []
      },                                      //models存储的数据store
      reducers: {
        save(state, { payload }) {                    //更新store,用新数据合并state的旧数据
          return { ...state, ...payload };
        }
      },
      effects: {
        * testFunc({ payload: params }, { call, put, select }) {   //dispatch请求的方法
          const { dataList } = yield select(state => state.system); //获取models中的state
          const { data } = yield call(services.testFunc, params);  //call,请求services里面的接口以及传参,可继续往后面加参数,跟JavaScript的call一样
          if (data && data.code == 0) {
            const data_ = data.data.content;
            yield put({ //put,必须发出action save,此action被reducer监听,从而达到更新state数据的目的
              type: 'save',                                        
              payload: {
                dataList: data_ || []
              }
            });
            return data_;                                          //返回response,可选
          }                                                        
        },
      },
      subscriptions: {                                             //订阅,在app.start()即启动项目时被执行
        setup({ dispatch, history }) {
          return history.listen(({ pathname, query }) => {
            // 进入 '/manager/system' 路由,会发起一个名叫 'save' 的 effect
            if (pathname === '/manager/system') {
                        //do sth... dispatch({ type: 'save', payload: query });
                    }
          })
        }
      }
    }

    注:call 会阻塞,在 call 方法调用结束之前,call 方法之后的语句是无法执行的,使得以同步的方式执行异步,如需无阻塞,则要引入 fork,用 yield fork 代替 yield call。

    services 层

    请求后台接口的方法,返回一个 promise 对象。

    import request from '@utils/request';
    
    export function rightSave(values) {
      return request(`/authirty/right/save`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(values)
      });
    }

    components 层

    dispatch

    与 effect 中的 put 方法相似,必须触发 action。 在 model 的 subscription 参数中使用。 在组件中,由 connect 过的组件中,组件的 props 中可以获取到 dispatch。

    import { connect } from 'dva'; 
    export default connect()(System);
    • 接口请求 方式一 (推荐): 使用 dispatch 调用 models 里面 effects/reducer 声明的方法,

    this.props.dispatch({
      type: 'system/testFunc',                                      //type,命名空间/effects方法名
      payload: params,                                              //payload,参数
    }).then(res => {})
    
    //直接赋值更新state
    this.props.dispatch({
      type: 'system/save',                                          //type,命名空间/reducer方法名
      payload: {
        rightDetail: {a:1}
      },                                              //payload,参数
    }).then(res => {})
    
    //请求全局model
    this.props.dispatch({
      type: 'global/getOrganizationList',                           //全局namespace/全局effects方法名
      payload: params,                                              //payload,参数
    }).then(res => {})

    方式二:dispatch 带 callback 回调函数作为第三个参数

    //组件中
    this.props.dispatch({
      type: 'system/testFunc',
      payload: params,
      callback: (res) => {
        if (!!res) {
          //do sth
        }
      }
    });
    
    //model中
    *testFunc({ payload, callback }, { call, put }){
      const { data } = yield call(services.rightSave, payload);
      if (data && data.code == 0) {
        !!callback && && callback(data);
      }
    }

    方式三 (少用):如果组件中不需要用到 model 存 store 时,直接引入 services 请求接口

    //组件中
    //使用new promise请求接口,service返回promise函数,待接口异步请求完才执行.then
    import * as service from '../services'; 
    new Promise((resolve) => {
      const ret = service.rightSave(param);
      resolve(ret);
    }).then((ret) => {
      if (ret && ret.code == 200) {
        //do sth
      }
    });
    
    // 或者
    // 现在的ajax框架返回的就是一个promise的话,可以直接方法名跟上.then()即可
    import { rightSave } from '../services';
    rightSave().then(res => {
      let data = res.data;
      if (data && data.code == 200) {
        //do sth
      }
    });

    connect

    方式一:mapStateToProps,class 继承组件和函数组件都能用这种

    接口请求完后,组件中引入 connect,获取 models 的数据放入当前组件 props 中

    import { connect } from 'dva'; 
    function mapStateToProps(state) { //state是项目所有的models
      const { selectList } = state.system; //获取namespace命名空间为system的models数据state
      const { organizationList } = state.global; //全局获取namespace命名空间为global的models数据state
      return {
        selectList,
        organizationList
      };
    }
    export default connect(mapStateToProps)(System);   //connect组件
    //或者直接解构
    export default connect(({ system, global: { organizationList } }) => ({ ...system, organizationList }))(System);

    方式二:es6 注解方式引入,只能用于 class 继承组件

    @connect(({ system, global: {organizationList} }) => ({ 
      ...system,
      organizationList
    }))
    class System extends React.Component{render(){return {<></>}}}

    withRouter

    withRouter 的作用:未经路由跳转的组件,如子组件想拿到路由的相关信息 location、history、match 等时可用,经路由跳转的页面则默认已有路由信息。

    FAQ:

    1. url 变化了,但页面组件不刷新,是什么原因? layouts/index.js 里如果用了 connect 传数据,需要用 umi/withRouter 高阶一下

    import withRouter from 'umi/withRouter';
    export default withRouter(connect(mapStateToProps)(LayoutComponent));

    2. 全局 layout 使用 connect 后路由切换后没有刷新? 需用 withRouter 包一下导出的 react 组件,注意顺序。

    import withRouter from 'umi/withRouter';
    export default withRouter(connect()(Layout));

    mock

    export default {
      // 支持值为 Object 和 Array
      'GET /api/users': { users: [1, 2] },
      // 支持自定义函数,API 参考 express@4
      'POST /api/users/create': (req, res) => { res.end('OK'); },
    }

    如请求接口 / api/list,数据返回 {users: [1, 2] }

    数据流程

    最后给大家总结一下 dva 的数据流向: * View 层 dispatch 操作 action –> 触发 models 层 effect 中相应方法 –> 触发 call 发起 services 层请求,获取接口数据 –> 触发 put 发起 reducer 处理相应的 action 更新数据 –> 更新 model 层中 state –> 触发 view 层的 render 方法进行重新渲染 –> 页面更新

    附上数据流向图

    参考文档

    umi 文档:https://umijs.org/zh/guide/

    dva 文档:https://dvajs.com/guide/

     

    构建项目node 环境全局安装 umi构建 umi 项目目录结构配置文件pages路由1. 约定式路由2. 配置式路由3. 权限路由4. 跳转路由models 层services 层components 层dispatchconnectwithRoutermock数据流程参考文档构建项目node 环境全局安装 umi构建 umi 项目目录结构配置文件pages路由1. 约定式路由2. 配置式路由3. 权限路由4. 跳转路由models 层services 层components 层dispatchconnectwithRoutermock数据流程参考文档


    https://preview.pro.ant.design/

    admin

    ant.design

    没有注册页面,编写一个注册页面

    先看:什么是一个 block 

     以前是全部自动下载,现在需要自己下载 block 

    umi block list 

    项目启动起来:

    Umi UI 是新的工具 

     两个用户,admin 和 user 

    pw 都是 ant.design

    user 比admin 权限少,看不到管理页

    登录后跳转到之前页面——通过 ?redirect 参数实现

     

      

     

      

     

     

     

     

      

     

     

    effects:副作用,这里用的 saga 的用法

    form:高阶组件用法

    可以收集段的值,也可以进行校验

    force: true —— 强行校验

      payload:携带的数据

    userAndRegister 命名空间,在models 里面定义的

      

    ...: ES6扩展新语法:

    https://blog.csdn.net/qq_30100043/article/details/53391308

     

     

     这个 interface 一会定义后端的接口需要用到

    @ 表示根目录 

     因为拦截了mock,直接校验通过

     

    JSON Web Token 入门教程- 阮一峰的网络日志

    www.ruanyifeng.com › 首页 › 档案
     
    2018年7月23日 - JSON Web Token(缩写JWT)是目前最流行的跨域认证解决方案,本文介绍它的原理和用法。 一、跨域认证的问题. 互联网服务离不开用户认证。

     

     

     不可以,想知道为什么得用 saga —— 基于 saga 都是  generator 模式

    对外umi,对内 bigfish 

    单点登录,非常复杂,不是一般前端能搞得定的

    qiankun:

    权限系统怎么处理的:

    来个 swagger 生成客户端请求 —— 今天不讲,下节课讲

  • 相关阅读:
    C++ 类初始化的顺序
    Given constant integers x and t, write a function that takes no argument and returns true if the function has been called x number of times in last t secs.
    Find out all the elements in A and B such that the A[i]B[j]=C[k]
    顺时针打印数组,美丽版
    Given a string S, find the longest palindromic substring in S.
    很多机器,每台机器上都有很一部分数据,如何输出分布在所有机器上的所有数据的median
    C++'s mutable and conceptual constness
    上20阶楼梯,可以一次迈1,2,3步,请问有多少种上法?
    Count smaller elements on right side in an array.
    一排房子,连续填色,成本最低的问题
  • 原文地址:https://www.cnblogs.com/cx2016/p/13166525.html
Copyright © 2011-2022 走看看