zoukankan      html  css  js  c++  java
  • Dva入门

    # Dva 入门
    概念:dva是体验技术部开发的react应用框架,将react-router/redux/redux-saga(异步操作)三个工具库包装在一起,简化API,让react应用更加方便、快捷。
    dva是framwork,不是library,类似emberjs,使用依赖库本身的语法。简化开发,相当于一个大的语法糖。
    数据流图:start-(connect)->view-(dispatch)->action
    state:通过创建一个state对象,保存整个应用状态,
    action:是一个对象,用来描述事件;
    connect方法:一个函数,绑定state到view;返回的也是react组件,成为容器组件,是原始的UI组件的容器在外面包裹一层state。接收两个参数mapStateToProps函数,mapStateToProps函数返回一个对象,用于建立state到props的映射关系。
    dispatch方法:一个函数,发送action到state;被connect的component会自动在props中拥有dispatch方法。




    Provider和connect()非常优雅的将全局store提供给了每一个组件。让每一个组件可以非常方便的去使用全局的数据。
    roadhog(如同webpack)
    1. Model对象的属性
    namespace:当前Model的名称。整个应用的state,由多个晓得Model的state以namespace为key合成。
    state:该Model当前的状态,数据保存在这里,直接决定了试图层的输出。
    reducer:Action处理器,处理同步动作,用来算出最新的state;
    effects:Action处理器,处理异步动作;基于redux-saga实现,典型的就是I/O操作、数据库读写。不能直接修改state,由action触发。
    Generator函数:effect是一个Generator函数,内部使用yield关键字,表示每一步的操作(不管是异步还是同步)
    call和put:dva提供多个effect函数内部的处理函数,常用的是call和put. call是执行异步操作,put发出一个action,类似dispatch.
    ```
    {
    namespace: 'count',
    state: 0,
    reducers: {
    add(state) { return state + 1 },
    },
    effects: {
    *addAfter1Second(action, { call, put }) {
    yield call(delay, 1000);
    yield put({ type: 'add' });
    },
    },
    }
    ```
    2. dva安装
    一、开始新项目的准备工作:
    1、安装dva-cli并确保版本在0.9.1或以上版本:
    npm install dva-cli -g
    检测版本号: dva -v



    2、创建项目名为‘wmz’的新项目:
    dva new wmz
    3、安装antd 和 babel-plugin-import ,babel-plugin-import 是用来按需加载 antd 的脚本和样式的,需要用tnpm 去下载ant插件。
     
    下载tnpm:有的不需要也可以
    npm install tnpm -g --registry=http://registry.npm.alibaba-inc.com
    tnpm install
    下载antd:
    npm install antd babel-plugin-import --save
    注意:下载完插件后,需要在.webpackrc文件中添加以下内容,才能使 babel-plugin-import 插件生效。
    "extraBabelPlugins": [
    ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }]
    ]
    4、准备工作做完之后,开始启动项目:
    npm start
    二、新项目实战
    1、创建路由,路由可以想象成是组成应用的不同页面。文件的位置:routes文件夹里面。
    2、添加路由信息到路由表,在router.js中进行编辑,先引入路由文件,再设置文件路径.
    此时,就已经可以在http:127.0.0.1:8000,看到页面信息了;
    3、编写UI Component,文件位置:component文件夹里;场景:在多个页面分享UI元素(或者在一个页面使用多次),在dva里可以把这部分抽成component。
    4、定义model,dva通过model的概念把一个领域的模型管理起来,包含同步更新state的reducer,处理异步逻辑的effects,订阅数据源的subscriptions。文件的位置在models文件夹里。
     
    在这个model里:
    namespace:表示在全局state上的key;
    state: 是初始值;
    reducer: 等同于redux里的reducer,接收action,同步更新state;
    最后记得一定要在index.js文件里载入model:
     
    app.model(require(‘./models/文件名’).default);
    5、connect方法:把model和component串联起来。文件位置:routers文件夹里。
    6、最后需要在index.js 中添加初始数据让项目run起来;
    const app = dva();
    三、项目模块安排
    项目的整体设计模式:
    1. 先设计model
    namespace 是 model state 在全局 state 所用的 key,state 是默认数据。
    异步处理:dva 通过对 model 增加 effects 属性来处理 side effect(异步任务),call,put;
    键盘订阅事件:subscription和model绑定,用于订阅一个数据源,然后根据dispatch需要的action,数据源可以是当前时间、服务器的websocket、keyword输入、geolocation变化、history路由变化等。
    2. 再设计component
    通过 props 传入两个值,count 和 dispatch,count 对应 model 上的 state,在后面 connect 的时候绑定,dispatch用于分发 action
    更新state是通过reducer处理的,也是唯一可以更新state的地方。
    3. 最后链接model和component
    router:写组件,接收dispatch和products两个参数;
    小案例:
    import React from 'react';
    import {connect} from 'dva';
    import ProductList from '../components/ProductList';
    
    const Products = ({dispatch,products}) => {
    function handleDelete(id){
    dispatch({//调用dva中的方法
    type:'products/delete',
    payload: id,
    })
    };
    return(
    <div>
    <h2>list of products</h2>
    {/*给组件绑定两个时间,删除事件和同步处理数据dva */}
    <ProductList onDelete={handleDelete} products={products}/>
    </div>
     
    )
    }
     
    export default connect(({ products})=>({
    products,
    }))(Products);
    ```
    models:定义model,对state进行管理,处理组件中的同步的方法;
    ```
    //在组件中调用
    export default {
    namespace : 'products',
    state : [],
    reducers : {
    'delete'(state,{payload:id}){//接收两个参数state和delete接收的参数
    return state.filter(item =>item.id !== id);//filter返回true或者false,是否保留该数据。
    }
    }
    
    }
    ```
    components:一个对象,接收父组件绑定在子组件上的方法和models;
    ```
    import React from 'react';
    import PropTypes from 'prop-types';//设置数据类型
    import {Table,Popconfirm,Button} from 'antd';
    
    const ProductList = ({onDelete,products}) =>{//接收方法
    const columns = [{
    title:'Name',
    dataIndex:'name'
    },{
    title:'Actions',
    render:(text,record)=>{ //编辑单元格
    return(
    //气泡框 onConfirm确认的
    <Popconfirm title="删除?" onConfirm={()=>onDelete(record.id)}>
    <Button>Delete</Button>
    </Popconfirm>
    );
    }
    }];
    return(
    <Table //表格
    dataSource = {products}
    columns = {columns}
    />
    )
    }
    export default ProductList;
    ## Dva源码解析
    1. roadhog 起的是 webpack 自动打包和热更替的作用。
    2. dva是一个杉树,返回一个app对象;目前 dva 的源码核心部分包含两部分,dva 和 dva-core。前者用高阶组件 React-redux 实现了 view 层,后者是用 redux-saga 解决了 model 层。
    3. src/index.js
    在这里,dva 做了三件比较重要的事情:
    使用 call 给 dva-core 实例化的 app(这个时候还只有数据层) 的 start 方法增加了一些新功能(或者说,通过代理模式给 model 层增加了 view 层)。
    使用 react-redux 完成了 react 到 redux 的连接。
    添加了 redux 的中间件 react-redux-router,强化了 history 对象的功能。
    4. provider本质上是一个高阶组件,也是一种代理模式,接收 redux 生成的 store 做参数后,通过上下文 context 将 store 传递进被代理组件。在保留原组件的功能不变的同时,增加了 store 的 dispatch 等方法。
    5. connect 也是一个代理模式实现的高阶组件,为被代理的组件实现了从 context 中获得 store 的方法。
    6. initialState 是 state 的初始数据,优先级高于 model 中的 state,默认为 {}。
    7. createLoading() 加载状态,在app.use(CreateLoading());根据state.loading.global指示全局loading状态。如果在组件中直接使用this.props.locading
    ## Dva
    1. 解决的主要问题

    简化了react-redux的部署文件的复杂度,能够快速上手;
    2. 主要接口:
    (1)后端接口:
    配置路由,在点击按钮后,在componentWillMount中通过this.props.dispatch派发,在model中执行effects、reducer等操作;在servers的文件夹下发送网络请求需要通过request.js文件,后台接收:
    export function patch(id, values) {
    return request(`/api/users/${id}`, {
    method: 'PATCH',
    body: JSON.stringify(values),
    });
    }

    (2)mock数据:在.roadhogrc.mock.js中添加配置
    export default {
    'GET /api/users': { users: [{ username: 'admin' }] },
    }
    export default {
    'POST /api/users': (req, res) => { res.end('OK'); },
    }
    在roadhogrc中进行配置proxy;若是get请求,则可以直接在url后面进行拼接;

    3. 主要执行路径

    用户操作后或者路由跳转->dispatch(action),同步直接通过reducer更改state,异步先触发effects,然后通过reducer最终改变state.

    4. 可配置及修改的类、函数和文件

    (1)路由:通过浏览器的History API可以监听浏览器url的变化,从而控制路由相关操作
    (2)在入口文件index.js中 可配置plugin/model/router
    state:model的状态数据,对象形式;
    action:是一个javascript对象,改变state的唯一途径。必须带有type属性,需要注意的是 dispatch 是在组件 connect Models以后,通过 props 传入的;
    dispatch:payload是需要传递的信息;通过props传入的dispatch函数;
    reducers:{ save(state,{payload: }){ return { }}}返回一个新值;
    effects:{fetch({payload},{call,put})} 不能直接修改state,由action触发。call是执行异步操作, put发出一个action,类似dispatch.

    import * as 自定义名 from '../services/service';

    effects: {

    *供组件调用的方法名({ payload: { 参数 }}, { call, put }) {

    const result = yield call(自定义名.service中的方法名, 参数);//如果使用 {参数} ,则是一个对象

    //把请求的数据保存起来
    //数据更新会带动页面重新渲染
    yield put({
    type: 'save', //reducers中的方法名
    payload:{
    data: result.data //网络返回的要保留的数据
    }
    })
    }
    },
    监听路由变化,当进入 /user 页面时,执行 effects 中的 fetch,以从服务端获取用户列表,然后 fetch 中触发 reducers 中的 save 将从服务端获取到的数据保存到 state 中。
    effects: {
    *fetch(action, { put, call }) {
    const users = yield put(fetchUsers, action.data);
    yield put({ type: 'save', data: users });
    },
    },
    *create({ payload: values }, { call, put }) {
    yield call(usersService.create, values);
    yield put({ type: 'reload' });
    },
    *reload(action, { put, select }) {
    const page = yield select(state => state.users.page);
    yield put({ type: 'fetch', payload: { page } });
    },
    Subscription :语义是订阅,用于订阅一个数据源,然后根据条件 dispatch 需要的 action。数据源可以是 当前的时间、服务器的 websocket 连接、keyboard 输入、geolocation 变化、history 路由变化等等。
    (3)在.webpackrc中通过添加字段来进行自定义antd主题;
    CSS Modules配置,
  • 相关阅读:
    Roofline Model与深度学习模型的性能分析
    卷积神经网络的复杂度分析
    CNN中卷积层的计算细节
    ImageNet 历届冠军最新评析:哪个深度学习模型最适合你?
    最新ICE源码编译安装
    CNN 模型压缩与加速算法综述
    YAML 与 front-matter
    VMware 虚拟机快照、克隆、磁盘扩容
    ubuntu16.04安装Nvidia显卡驱动、CUDA8.0和cudNN V6
    宏使用 Tricks
  • 原文地址:https://www.cnblogs.com/naniandongzhi/p/9257399.html
Copyright © 2011-2022 走看看