2019-09-27umi+dva+ant-design项目搭建

新建文件夹在webstorm中打开itcast-react

一、安装和使用yarn包管理工具

参考:yarn常用用法

推荐使用 yarn 管理 npm 依赖,并使用国内源(阿里用户使用内网源)。

配置yarn国内源:


yarn config set registry https://registry.npm.taobao.org --global

yarn config set disturl https://npm.taobao.org/dist --global

# 国内源
$ npm i yarn tyarn -g
# 后面文档里的 yarn 换成 tyarn
$ tyarn -v

# 阿里内网源
$ tnpm i yarn @ali/yarn -g
# 后面文档里的 yarn 换成 ayarn
$ ayarn -v

tyarn 是走的国内淘宝的npm.taobao.org镜像
当我们通过yarn安装太慢的时候,可以借助tyarn来安装我们所需要的依赖

1.tyarn 安装
npm install yarn tyarn -g

2.tyarn 安装、升级、卸载和yarn的一样
//eg:
tyarn add antd

3.全局安装umi
#下面开始安装umi 
tyarn global add umi 
umi #进行测试
4.添加yarn安装目录到环境变量
  • 如果提示 umi: command not found,你需要将 yarn global bin 路径配置到环境变量中,方法如下:
# windows系统:
# 获取 global bin 的路径
$ yarn global bin
C:\Users\Administrator\AppData\Local\Yarn\bin
# 复制上面的 global bin 的路径,添加到系统环境变量 PATH。

坑:配置完环境变量之后还是非内部或外部命令-----> 只要关闭Terminal再重新开一下就好

二、初始化测试项目目录

1.初始化yarn环境
  • tyarn init -y
  • 此时文件夹中多出来package.json文件
2.通过umi命令创建index.js
  • umi g page index
  • 可以看到在pages下创建好了index.js和index.css文件
3.通过命令行启动umi的后台服务,用于本地开发
  • umi dev
4.添加本地开发环境中umi依赖
  • tyarn add umi --dev

三、创建umi-dva-react开发环境

  • 新建文件名为umi-react
  • 右键在webstorm中打开
  • tyarn init -y
  • tyarn add umi --dev
  • 新建目录以及文件/config/config.js
    写入:
//导出一个对象,暂时设置为空对象,后面再填充内容 
export default {};
  • 新建目录及文件:/src/pages/HelloWorld.js
    写入:
export default () => { return <div>hello world</div>; }
  • tyarn add umi-plugin-react --dev

四、umi项目中开启dva进行使用

  • /config/config.js中进行如下修改:
export default {
    plugins:[
        ['umi-plugin-react',{
            // 开启dva
            dva:true
        }]
    ]
};
  • 创建model层管理数据
    • 新建目录及文件/src/model/DataList.js
      写入:
export default {
    namespace:'list',
    state:{
        data:[1,2,3],
        maxNum:3
    }
}

注意:在umi中,约定大于配置,约定在src/models文件夹中定义model,所以,在 该文件夹下创建ListData.js文件,通过@connect方法与view进行连接

坑:modules和models容易搞混,module(模块),model(模型),如果一不小心写错,会报错:Could not find "store" in the context of "Connect(List)". Either wrap the ...,名字改过来就好了,如果改名之后还不行,不要慌张,Ctrl+C终结服务,再重新umi dev就好了

  • 按需引入connect方法 import { connect } from 'dva'
  • 在view中使用的时候用到ES6语法中的修饰符
  • @connect函数接收两个参数,第一个参数接收一个函数,这个函数的参数为state,state是一个全局state变量,需要借助命名空间来指定对应的具体module,这个函数的作用是返回module中的数据,并且绑定到this.props上面,所以最后记得要return
 // /src/pages/List.js
import React,{Component} from 'react'
// 导入dva的connect方法进行page和model的连接
import { connect } from 'dva'

// 定义一个命名空间
const namespace = 'list'
// 定义@connect函数第一参数(函数)
const mapStateToProps = state => {
    // 此时的state是一个全局对象
    // 必须搭配namespace下标形式映射到对应的model
    // 并且可以直接获取对应model中state上的值
    const listData = state[namespace].listData
    const maxNum = state[namespace].maxNum
    // 此函数需要return一个对象
    // 该对象将直接映射到该组件的this.props上
    return {
        listData,
        maxNum
    }
}

// 通过@connect修饰符建立映射
@connect(mapStateToProps)

export default class List extends Component{
    render(){
        return <div>
            {
                this.props.listData.map((item,index) => {
                    return <li key={index}>{item}</li>
                })
            }
            <button>增加</button>
        </div>
    }
}
页面效果
  • 流程说明:
      1. umi框架启动,会自动读取models目录下model文件,即ListData.js中的数据
      1. @connect修饰符的第一个参数,接收一个方法,该方法必须返回{},将接收到 model数据
      1. 在全局的数据中,会有很多,所以需要通过namespace进行区分,所以通过 state[namespace]进行获取数据
      1. 拿到model数据中的data,也就是[1, 2, 3]数据,进行包裹{}后返回
      1. 返回的数据,将被封装到this.props中,所以通过this.props.listData即可获取到 model中的数据

五、dva框架中修改state值的操作方法

1、首先,在model层(/models/ListData.js)中对操作方法进行定义
// 定义修改状态值的方法集合reducers
reducers:{
    addNewData:function(state){ // 这里的state是指更新之前的状态数据
        let maxNum = state.maxNum + 1
        let newArray =[...state.listData,maxNum]
        // 操作完业务逻辑之后,通过return即可更新state对象
        // 类似于独立组件的this.setState()方法
        return {
            listData:newArray,
            maxNum
        }
    }
}
2、在src/pages/List.js中绑定事件并且传递action

原理说明:

  • @connect(参数1,参数2)
  • 参数1将page层和model层进行连接,返回model中的数据,并且将数据绑定到this.props上
  • 参数2将定义的函数绑定到this.props中,并且可以调用model层定义的函数
  • 参数2也是一个函数,接收dispatch参数,此参数作用是调用model层定义的函数,有返回值,返回值是一个对象,其中的函数可以被this.props调用
  • 参数2函数的返回值对象的函数中,通过调用dispatch方法,传入对象即可调用model中定义的方法,所传入对象的第一个值格式为type:namespace + '/model中函数名'
    代码如下:
// 定义@connect函数的第二个参数(函数)
onst mapDispatchToProps = dispatch => { // 需要接收dispatch作为参数
   return { // 返回一个装满函数的对象,直接绑定到this.props上
       add : function () {
           dispatch({ // 在返回的函数内部调用dispatch方法,参数为一个对象
               type:namespace + '/addNewData' // 对象第一个值为type,格式为:namespace + '/model中的方法名'
           })
       }
   }
/ 通过@connect修饰符建立映射
connect(mapStateToProps,mapDispatchToProps)

// 绑定事件:
<button onClick={this.props.add}>增加</button>
界面效果

坑:dispatch哪来的?----->内置函数

六、dva框架model中请求数据

  1. 创建目录以及文件/src/Utils/request.js
    写入内容(固定写法):
// /src/util/request.js
// import fetch from 'dva/fetch';

function checkStatus(response) {
    if (response.status >= 200 && response.status < 300) {
        return response;
    }

    const error = new Error(response.statusText);
    error.response = response;
    throw error;
}

/**
 * Requests a URL, returning a promise.
 *
 * @param  {string} url       The URL we want to request
 * @param  {object} [options] The options we want to pass to "fetch"
 * @return {object}           An object containing either "data" or "err"
 */
export default async function request(url, options) {
    const response = await fetch(url, options);
    checkStatus(response);
    return await response.json();
}
  1. model文件中,和namespacestatereducers平级,新增effects配置,用于异步请求加载数据
    // 增加effects配置用于进行异步数据请求
    effects: {
        *initData(params, sagaEffects) { //定义异步方法---->generator函数
            const {call, put} = sagaEffects; // 需要传入sagaEffects以获取到call、put方法
            const url = "/ds/list"; // 定义请求的url
            let data = yield call(request, url); //执行请求,call方法需要request作为参数
            yield put({ // 调用reducers中的方法并且传入对象作为参数,对象中有type和data两个属性
                type : "addNewData", //指定调用方法名
                data : data //ajax请求传递回来的数据
            });
        }
    }
  1. 由于call方法需要request作为参数,所以在头部引入
    import request from '../util/request';
  2. 调用时机:ComponentDidMount
componentDidMount(){
    this.props.init ()
}
  1. mapDispatchToProps中建立映射
    return的对象中新增:
init : () => {
            dispatch({
                type:namespace + '/initData'
            })
        }

七. 处理请求的url地址

由于url = "/ds/list"不存在所以会报错

url地址不存在

  • mock模拟请求服务器
    • 新建目录及文件/src/mock/MockListData.js
      写入:
export default {
    'get /ds/list': function (req, res) { //模拟请求返回数据
        res.json({
            data: [1, 2, 3, 4, 5],
            maxNum: 5
        });
    },
}
  • 坑:一定要重启服务才能正确请求到!

  • 注意请求回来的数据值类型,需要和state类型一致


    model中返回值类型
  • reducers中被触发的函数的第二个参数为effects中函数传来值,其上的result.data和state类型一致,可以直接return并修改sate


    image.png

八.项目中使用antd

  1. umi+dva中引入antd
    在 umi 中,你可以通过在插件集 umi-plugin-react 中配置 antd 打开 antd 插件,antd 插件会帮你引入 antd 并实现按需编译。


    config.js中配置以引入antd
  2. 新建文件用于演示/src/pages/MyTabs.js

坑:在config.js中antd:true之后仍然要重启服务

ES6对象的结构赋值特性:

  1. 通过同一对象中属性扩散可覆盖属性值
const state = {
    num:0
}
let num = 2
// 将state对象结构,num实际为num = num,覆盖之前state解构出来的属性值
console.log({...state,num})  // {num:2}

const state1 = {
    num1:0,
    a:21,
    b:12
}
let [num1,a,b] = [23,54,67]
console.log({...state1}) // {num1: 0, a: 21, b: 12}

const state3 = {
    x:0,
    y:21,
    z:12
}
let [x,y,z] = [23,54,67]
console.log({...state3,y,z}) // {x: 0, y: 54, z: 67}

  1. 区分变量和模式
    变量必须与对象的属性同名,才能取到正确的值,如果没有对应的同名属性,取不到值的话,值为undefined
var {bar, foo} = {foo:'aaa',bar:'bbb'}//foo的值是'aaa',bar的值是'bbb'
//注意真正被赋值的是谁
var {foo:baz} = {foo:"aaa",bar:"bbb"}//baz的值是"aaa"而不是foo的值是“aaa”,foo是个“模式”

谁后面有“:”,谁就是模式,并不是变量

  1. 从对象的多个属性中只继承一个属性
const state = {
    size: 'large',
    icon:'download'
  };
let { size } = state
console.log( value )

扩展资料:

#Umi + Dva + Antd的React项目实践
#React + Dva + Antd + Umi 概况
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容