【Umi 一】 Umi 搭建配置

蚂蚁金服开源的企业级React框架,并不是UI框架

1.特性

  1. 开箱即用,内置 reactreact-router ...
  2. 类似 next.js 且功能完备的路由约定,同时也支持手动配置路由的方式;
  3. 完善的插件体系,高性能,通过插件支持PWA、以路由为单元的code splitting等等;
  4. 支持静态页面导出,适配各种环境,如中台业务、无线业务、egg、支付宝钱包
  5. 开发启动快,支持一键开启dll
  6. 一键兼容IE9、基于 umi-plugin-polyfills
  7. 支持TypeScript
  8. dva 数据流的深入融合,支持duck directory、model的自动加载、code splitting等等
2.dva 是React应用框架,封装了 ReduxRedux-sagaReact-router 三个React工具库,目前 React 最流行的数据流解决放案;


1. State:一个对象,保存整个应用状态;
2. View:React组件构成的视图层;
3. Action:一个对象,描述事件
4. connect():绑定```State``````View```
5. dispatch():发送```Action``````State```

3.dvaumi 的约定

        1.src 源码:pages(页面)、components(组件)、layout(布局)、model(数据模型)

        2.config 配置

        3.mock 数据模拟

        4.test 测试

4.全局安装脚手架: npm i umi -g
 

快速上手

1、创建一个项目目录:mkdir myumi
2、cd myumi 
3、npm init:生成 package.json
"scripts": {
    "start": "umi dev",
    "build": "umi build"
}
4、创建 src 目录,生成 pages 目录,默认使用约定式路由
cd src
umi g page index  // index.js和index.css
umi g page about  // bout.js和about.css

5、运行项目:npm start,自动编译生成页面配置 /src/pages/.umi 目录,且项目是热部署;

http://localhost:8000/  --> index.js
http://localhost:8000/about  --> about.js

6、引入公共 css (根据个人需求,可要可不要)

在 src 目录下新建 global.css/.less 

7、创建全局布局 layouts,如公共头部、尾部  (根据个人需求,可要可不要)

src/layouts 目录中的 index.js 将成为项目的定级布局页面,使用 {props.children} 显示 src/pages 目录中的组件。

在 src 目录下,创建文件夹 layouts
在 layouts 目录下,创建 index.js、index.less
import styles from './index.css';
import {Layout} from 'antd';
const {Header, Content, Footer} = Layout;

export default (props) => {
    return (
        <Layout>
            <Header>
                <div style={{color: 'white'}}>王者资料库</div>
            </Header>
            <Content style={{padding: '0 50px'}}>
                {props.children}
            </Content>
            <Footer style={{textAlign: 'center'}}>footer</Footer>
        </Layout>
    )
}

约定式路由嵌套 (Link、history)

1、当出现 _layout.js 页面时默认为父组件页面,通过 {props.children} 显示子组件内容;

2、嵌套路由:/users,创建 pages/users 目录

umi g page users/_layout    // pages/users/_layout.js、_layout.css

        1.pages/users/_layout.js

import React from 'react';
import styles from './_layout.css';

export default (props) => {
  return (
    <div className={styles.normal}>
      <h1 className={styles.title}>Page users/_layout</h1>
      <div>{props.children}</div>
    </div>
  );
}

        2.为 _layout.js 创建子组件,users 的首页 index.js

 umi g page users/index    // pages/users/index.js、index.css

         3.访问嵌套路由:http://localhost:8000/users

 3、约定 [] 包裹的文件或文件夹为动态路由、users/[name].js 对应路由为 /users/:name

  1. users 目录中,再创建 [name].js、[name].css
  2. 访问 [name].jshttp://localhost:8000/users/xxx

4、跳转路由 (Link,history)

         1.users/index.js

import React from 'react';
import styles from './index.css';
import {Link} from 'umi';

export default () => {
    const userList = [
        {id: 1, name: 'Tim'}, {id: 2, name: 'Jarry'}
    ]
  return (
    <div>
      <ul>
      {
          userList.map(item => (
              <li key={item.id}>
                  <Link to={`/users/${item.name}`}>{item.name}</Link>
              </li>
          ))
      }
      </ul>
    </div>
  );
}

          2.users/[name].js

import React from 'react';
import styles from './[name].css';
import {history} from 'umi';

export default (props) => {
  return (
    <div>
      <h1 className={styles.title}>Page users/[name]</h1>
      <h2>{props.match.params.name}</h2>
        <button onClick={()=>props.history.goBack()}>返回</button>
    </div>
  );
}

配置式路由

1、配置式路由一旦创建,约定式路由自动失效,umi不会再自动创建路由;

2、在项目根目录下创建 config 目录,并创建 config.js文件;

// 没有设置全局 layouts 布局
export default {
    // 路由配置:路径相对于 src/pages
    routes: [
        {path: '/', component: './index'},
        {path: '/about', component: './about'},
        {
            path: '/users',
            component: './users/_layout',
            routes: [
                {path: '/users', component: './users/index'},
                {path: '/users/:name', component: './users/[name]'},
            ]
        },
        {component: './notfound'} // 404页面,上面的所有路由都没有匹配时,则匹配404页面
    ],
}
// 设置了全局 layouts 布局
export default {
    // 路由配置:路径相对于 src/pages
    routes: [
        {
            path: '/', 
            component: '../layouts/index',
            routes: [
                {path: '/', component: './index'},
                {path: '/about', component: './about'},
                {
                    path: '/users',
                    component: './users/_layout',
                    routes: [
                        {path: '/users', component: './users/index'},
                        {path: '/users/:name', component: './users/[name]'},
                    ]
                },
            ]
        },
    ],
}

3、相应地,创建404组件:umi g page notfound

4、引入ant design UI库

npm i antd -S
npm i @umijs/preset-react -D (umi3升级)

         1.config/config.js

    export default {
        //路由配置
        routes: [...],
        antd: {},
    }

          2.使用时需要导入组件,因为是按需加载

import {Button} from 'antd';

<Button type="success">antd Btn</Button>

引入dva

1、dva 主要是软件分层的概念

          1.Page 负责与用户直接交互:渲染页面、接收用户的操作输入,侧重于展示型和交互逻辑;

          2.Model 负责处理业务逻辑,可以理解成一个维护页面数据状态的对象,为 Page 做数据、状态的读写等操作;

    export default {
        namespace: 'goods',  // model的命名空间,区分多个model
        state: [],  //初始状态
        effects: {  //异步操作
        },
        reducers: {}
    }

            3.Service 主要负责与HTTP做接口对接,跟后端做数据交互,读写数据;

2、dva 已经融合进了 umi,在 config/config.js 中打开 dva 的开关

antd: {},
dva: {}

基本用法

umi g page goods
npm i axios -S

1、路由配置:config/config.js (如果使用约定式路由,则无须配置)

routes: [
    { path: "/goods", component: "./goods" },
]

2、在项目根目录下创建 mock/goods.js,模拟接收请求,响应数据

let data = [
  {title: '单页面'},
  {title: '管理项目3'}
]
export default {
  'get /api/goods': function(req, res){
    setTimeout(() => {
      res.json({result: data})
    }, 1000)
  }
}

3、Modelsrc/models/goods,js

import axios from 'axios';

//调接口的逻辑应该放在 Service 层
function getGoods(){
  return axios.get('/api/goods')
}

export default{
    namespace: 'goods',  // 命名空间,如果省略,则以文件名作为命名空间
    state: [],
    effects: {
        *getList(action, {call , put}){ // 异步操作
            const res = yield call(getGoods);  // 发起请求
            yield put({type: 'initGoods', payload: res.data.result})  // 派发异步action: initGoods 
        }
    },
    reducers: {
        initGoods(state, action){
            return action.payload
        },
        addGood(state, action){
            return [...state, {title: action.payload.title}]
        },
        delGood(state, action){
            return [...state.slice(0,action.payload.index),...state.slice(action.payload.index+1)];
        }
    }
}

4、pages/goods.js

import React, { Component} from 'react';
import styles from './goods.css';
import {connect} from 'dva';

// @connect 必须放在 export default class 前面
@connect(
  state => ({
    goodList: state.goods, // 从指定命名空间内获取state
    loading: state.loading // 通过loading命名空间获取加载的状态
  }), 
  {
    getList: () => ({
      type: 'goods/getList' // action的type需要以命名空间为前缀,后跟reducer
    }),
    addGood: title => ({
      type: 'goods/addGood',
      payload: {title}
    }),
    delGood: index => (
        {
            type: 'goods/delGood',
            payload: {index}
        }
    )
  }
)

export default class extends Component{
  componentDidMount(){
    this.props.getList(); // 触发事件,发起请求,获取数据
  }
  render(){
    if(this.props.loading.models.goods){
        // 命名空间goods 的请求在加载中
      return <div>loading</div>
    }
    return (
      <div>
        <ul>
          {
            this.props.goodList.map((good, index) => {
              return <li key={index}>{good.title}<button style={{marginLeft: '100px', marginBottom: '10px'}} onClick={() => this.props.delGood(index)}>删除</button></li>
            })
          }
        </ul>
        <button onClick={() => this.props.addGood('商品3')}>添加</button>
      </div>
    )
  }
}

【常见报错问题】

1、reactjs页面无法引入umi/link

【Umi 二】reactjs页面无法引入umi/link

 2、Path must be a string. 

【Umi 三】 Umi项目启动报错:Path must be a string.

3、Cannot find module 'umi'

【Umi 四】 Cannot find module 'umi'

参考文章:umi

原文地址:https://www.cnblogs.com/rachelch/p/13878202.html