dva深入理解 react_react中 安装dva不使用dva cli - CSDN
  • PC管理端架构 技术构成: 1)基础框架React ----性能优越、稳定可靠 虚拟DOM技术,网页在内存拼接,一次批量快速渲染 ...3)数据状态管理Dva 跨组件数据状态共享,避免复杂的数据传递,任一组...

    PC管理端架构

    技术构成:
    1)基础框架React                ----性能优越、稳定可靠
    虚拟DOM技术,网页在内存拼接,一次批量快速渲染

    2)UI组件库Ant Design        ----成熟、丰富、稳定的React UI组件库
    文档说明清晰,使用人数多,常用UI组件多,界面美观,可定制性高

    3)数据状态管理Dva
    跨组件数据状态共享,避免复杂的数据传递,任一组件可以随意获取另一组件数据

    4)打包工具WebPack
    可以使用现金的ES6/ES7/ReactJSX语法
    可以使用样式缩略语法less
    代码分割、合并、压缩

    工程脚手架——根目录

    .gitignore        --git忽略文件夹
    .happypack        --WebPack多进程打包插件
    dist             --最终打包生成的html+css+js
    node_modules     --node.js依赖包目录
    src                --开源目录
    package-lock.json        --node.js锁定包版本文件
    package.json            --node.js包管理记录文件
    README.md                 --工程说明文档
    webpack.config.js         --webpack配置文件
    webpack.dll.config.js     --Webpack Dll配置文件

    工程脚手架——src目录

    assets            --静态资源目录(样式、图片、字体、json)
    config             --站点配置文件
    css                --站点全局样式
    pages            --业务页面目录
    pubBiz            --业务组件(构件)目录
    utils            --公共工具类
    widget            --基础组件目录
    favicon.ico        --站点地址栏图标
    index.html        --单页面模板
    index.js         --入口程序
    router.js         --路由配置
    theme.js         --主题设置

    工程脚手架  - 业务页面

    xxxServ.js             接口服务层 对应RESTFull接口的访问路径
    xxxMod.js             业务处理层 接口请求、数据状态处理
    xxxView.jsx         视图展示层 描述UI长什么样子、按钮点击响应处理
    xxxStyle.less         页面的样式 UI元素的样子

    安装yx-npm命令行(CLI)工具

    外网安装
         1. 需要先登录私有npm仓库 
            npm login  --registry  https://npm.dtyunxi.cn
        提示:安装过程提示输入的用户名、密码、邮箱由云徙提供
        2. 继续安装yx-npm
             npm install yx-npm  -g  --registry  https://npm.dtyunxi.cn
    2. 执行初始化命令(会提示输入项目名name、端口号port)
            yx-npm make mgmt
    3. 安装包依赖(进入项目根目录)
            npm install
    4. 启动项目
            npm run dev
    5. 浏览器访问(port为步骤2的端口号,登录用户名、密码、图形验证码随便填点击登录进去)
            http://localhost:port

    编写雇员CRUD

    编写雇员列表
            yx-npm list  -e employee  -z 雇员
    提示:
        -e 为所要生成模块的英文名
        -z 为所要生成模块的中文名
    编写雇员编辑页
            yx-npm edit  -e employee  -z 雇员
    编写雇员详情页
            yx-npm detail  -e employee  -z 雇员
        提示:以上命令会在当前目录生成一个dest目录,子文件夹为一个完整的模块
        cfgMenu.js为生成的菜单配置内容,可拷贝对应内容到config/menu.js中,注意修改value的值cfgRouter.js为生成的路由配置内容,可拷贝对应内容到src/router.js中其余的文件拷贝到biz目录下对应的文件夹,然后根据需要修改文件依赖路径

    框架数据流驱动走向

    重点介绍3层,
    1)xxxServ.js             接口服务层

    export function doit (body) {
    	return request({
    		method: "post",
    		url: `${wechatApi}/doit`,
    		data: JSON.stringify(body),
    	})
    }

    这里是请求后台接口的方法,其中这里的request是封装了axios的函数,所以他返回的是一个promise对象,URL就是要请求的地址,body就是请求参数了

    request剖析如下:

    import axios from "axios"
    
    export default async function request(options) {
    	let response
    	try {
    		response = await axios(options);
    		return response
    	} catch(err) {
    		return response
    	}
    }
    

    2)xxxMod.js             业务处理层 

    export default {
    	namespace: "test",	//命名空间名字,必填
    	state:{num: 0},		//state就是用来放初始值的
    
    	//能改变界面的action,这里不能做数据处理,只能用来return state从而改变界面
    	reducers: {
    		addNum(	//addNum可以理解为一个方法名
    		
    		//此处的state就是上面出事的state,这里理解是旧state
    		state, { payload: { num }}	//num是传过来的,名字可任意起,不是state中的num,这接受一个action
    		){
    		//return新的state,这样页面就会更新,吧num:num重新赋值,这样后面赋值的num就会覆盖前面的。
    		return {...state, num}
    		},
    	},
    
    	//ES6新语法,与后台交互,处理数据逻辑的地方,实现异步处理
    	effects: {
    		*fetchNum({ payload2 }, {call, put, select }) {
    			//fetchNum方法名,payload2是传来的参数,是个对象,如果没参数可以写成{_,{call,put,select}}
    			const { data } = yield call(myService.diot, {anum:payload2.numCount})
    			//myService是引入service层的文件名,diot是对应的接口函数名,anum是后台要求传的参数, data就是后台返回来的数据
    
    			const m = yield select((state) => state.test.num)		//select就是用来选择上面state里的,这里没用上
    			yield put({
    				//这就是reducer中addNum方法,put用来出发reducer中的方法,payload就是传过去的参数。同时也能触发等级effects里的其他方法
    				type: "addNum",		
    				payload: {
    					num: data,	//把后台返回的数据赋值给num, 如果方法是来自reducer则必须同名
    				},
    			})
    		},
    		*fetchUser(_,{call, put}) {
    			//....
    		},
    		subscriptions: {
    			//订阅监听,如若监听路由,则是页面的入口点
    			setup ({ dispatch, history, query }) {
    				return history.listen(async ({ pathname, search, query}) => {
    					if(pathname === '/testdemo') {
    						//进入testdemo时,就会触发fetchUser方法
    						dispatch({ type: "fetchUser" })
    					}
    				})
    			}
    		}
    	}
    },

    xxxView.jsx         视图展示层

    clickHandler = () => {
    	dispatch({
    		type: "test/fetchNum",
    		//这里就会触发mod层effect里的方法(也可以直接触发reducer中方法)
    		//test就是mod命名空间名字
    		payload:{
    			numCount: ++1,
    		},
    	})
    } 
    

    总结数据趋向走向流程:

    点击页面按钮 -> 触发clickHandler -> 触发mod层effect的fetchNum -> 触发serv层doit,获取后台返回数据
    -> 触发mod层的addNum,返回数据更新mod层的state -> components应用mod层中的state的num
    -> 触发页面render方法重新渲染 -> 界面更新

    render方法什么时候会触发

    当state或props变化时就会触发render,我们一般在render里只获取 props 和 state,尽量不做逻辑处理 (数据逻辑处理基本在render上面的函数或者models中处理)。当父组件给子组件传递props时,子组件那个props最好不要在render里面做逻辑计算赋值,不然传递过去,子组件有可能拿不到最新的值。比如传了个数组arr,arr在render里做了数据处理,赋值,render会运行多次(这里举例3次)所以结果可能是 [1,2,3] [1,2,3] [1,2],子组件拿到的值是[1,2,3]而不是最终的[1,2],所以当你出现子组件无法获取父组件传递过来最后正确的值,看看是不是值在render做了运算赋值,解决方法就是把数据逻辑放在models层处理,然后再返回,这样就没问题了。

    页面要应用mod层的数据要用connect

    import { Compoent } from 'react'
    import { connect } from 'dva'
    
    class TheDemo extends Compoent {
    	clickHandler = () => {xxxx}
    	render() {
    		const {num} = this.props	//获取下面的num
    		return (
    			<div>
    				<button onClick = {this.clickHandler}</button>
    				<p>{num}</p>
    			</div>
    		)
    	}
    }
    
    //字面意思就是把mud的state变成组件的props
    function mapStateToProps(state) {
    	const { num } = state.test 			//test就是mod命名空间名字
    	return {
    		num,	//在这return,上面才能获取到
    	}
    }
    
    export default connect(mapStateToProps) (TheDemo)

     

    展开全文
  • React-Dva学习

    2018-10-12 17:00:01
    npm install dva-cli -g or yarn global add dva-cli 创建新应用 安装完cli工具以后就可以在命令行访问到, 为了方便学习,我们可以使用命令创建 // 创建一个标准项目 dva new my-app // 创建一个学习的 简答...

    安装

    • 安装脚手架
    npm install dva-cli -g
    or
    yarn global add dva-cli
    
    • 创建新应用

    安装完cli工具以后就可以在命令行访问到,

    为了方便学习,我们可以使用命令创建

    // 创建一个标准项目
     dva new my-app
    // 创建一个学习的 简答的demo
    dva new my-app --demo
    
    
    • 启动项目

    进入项目目录,执行启动命令,启动开发服务器

    // 启动项目
    npm start 0r yarn start
    
    // 等到看到以下信息输出,就可以启动项目了
    Compiled successfully!
    The app is running at:
     http://localhost:8000/
    

    使用antd

    • 安装antd

    通过 npm 安装 antdbabel-plugin-importbabel-plugin-import 是用来按需加载 antd 的脚本和样式的,

    npm install antd babel-plugin-import --save
    Or 
    yarn add antd babel-plugin-import --save
    
    • 编辑 .webpackrc,使 babel-plugin-import 插件生效。
    {
    +  "extraBabelPlugins": [
    +    ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }]
    +  ]
    }
    

    注:dva-cli 基于 roadhog 实现 build 和 dev,更多 .webpackrc 的配置详见 roadhog#配置

    定义路由

    • 新建文件,创建路由表
    // 1.在src下新建pages目录
    // 2.新建在src/pages新一个js文件,命名名为Login.js
    // 3.src/pages/Login.js 文件内容如下
    
    import React from 'react';
    
    const Login = (props) => (
      <h2>Login</h2>
    );
    
    export default Login;
    
    • 添加路由信息到路由表
    // routers.js 新增一下代码
    // 引入模板
    import Login from './pages/Login'
    
    // 添加Route
    <Route path="/login" exact component={Login} />
    

    现在就可以在浏览器查看路径了

    定义model

    • model是一个对象,提供了注册model方法app.model({}),取消注册方法app.unmodel(namespace), 需要特别注意的是: 取消 model 注册,清理 reducers, effects 和 subscriptions。subscription 如果没有返回 unlisten 函数,使用 app.unmodel 会给予警告

    • namespace:,字符串,命名空间,我们在对该model进行CRUD的时候通过这个空间来方法具体的数据或者actions

    • reducers: 一个对象, 里边方react-redux里的dispatch函数,我们出发同步的action,然后经过reducers里对应的函数处理,然后更新store

    • effects: 对象,副作用。当我们在开发的时候如果有异步的操作,会先出发effects里的函数,然后拿到结果以后再出发reducers里的同步函数对store进行CRUD

    • subscriptions:对象, 订阅 在这里我们监听url变化,当切换到todos的时候,调用后台接口异步渲染数据

    • 下边是一个简单的model

    // model demo
    app.model({
      // 命名空间,它就是之前combineReducers里边的key值
      namespace: 'counter',
      state: { // 状态
        number: 0
      },
      // 处理器, 这里可以直接定义子reducer
      reducers: {
        // 这个函数会在派发一个动作 'counter/add'的时候触发add函数
        add (state, action) {
          return {number: state.number + 1}
        },
        minus (state, action) {
          return { number: state.number - 1 }
        }
      }
    })
    

    定义组件组件

    dva里所有的组件都是函数组件,只有在特殊情况下,如需要声明周期的组件才会使用类组件

    定义一个简单的组件如下:

    function Counter({ number, dispatch}) {
      return (
        <div>
          <p>{number}</p>
          <button onClick={()=> dispatch({type: 'counter/add'})} >add</button>
          {/* <button onClick={add} >add</button> */}
        </div>
      )
    

    actions派发

    let actions = {
      add () {
        return {
          type: 'counter/add'
        }
      }, 
      mins () {
        return {
          type: 'counter/minus'
        }
      }
    }
    
    // 使用connect连接
    let mapStatetoProps = state => state.counter
    let ConnectCounter = connect(
      mapStatetoProps
    )(Counter)
    

    配置动态加载组件

     import dynamic from 'dva/dynamic';
    
    const UserPageComponent = dynamic({
      app,
      models: () => [
        import('./models/users'),
      ],
      component: () => import('./routes/UserPage'),
    });
    

    来一个栗子

    • 使用dva初始化一个demo项目,在这个demo的基础上写一个技术的小练习

    • 初始化项目, dva new counter --demo

    • 进入counter/src/index.js

    • 开始改写

    import React, {Component} from 'react';
    import dva, { connect } from 'dva'
    
    let app = dva()
    // combineReducers({
    //   counter: counter
    // })
     // state 合成后的样子
    //  {
    //    counter: {number: 1}
    //  }
    
    // 配置模型
    app.model({
      // 命名空间,它就是之前combineReducers里边的key值
      namespace: 'counter',
      state: { // 状态
        number: 0
      },
      // 处理器, 这里可以直接定义子reducer
      reducers: {
        // 这个函数会在派发一个动作 'counter/add'的时候触发add函数
        add (state, action) {
          return {number: state.number + 1}
        },
        minus (state, action) {
          return { number: state.number - 1 }
        }
      }
    })
    
    
    // 使用action派发
    let actions = {
      add () {
        return {type: 'counter/add'}
      }, 
      mins () {
        return {type: 'counter/minus'}
      }
    }
    
    // 定义组件, dva里所有的组件都是函数组件 
    // function Counter({ number, dispatch}) { // 之前写法
    //   return (
    //     <div>
    //       <p>{number}</p>
    //       <button onClick={()=> dispatch({type: 'counter/add'})} >add</button>
    //       {/* <button onClick={add} >add</button> */}
    //     </div>
    //   )
    // }
    function Counter({ number, add }) {// dva的写法
      return (
        <div style={{border: '1px solid #06c', width: 200, height: 3 00, margin: '100px auto 0', padding: 20}}>
          <p>{number}</p>
          <button onClick={add} >add</button>
        </div>
      )
    }
    // 使用connect连接
    let mapStatetoProps = state => state.counter
    // let ConnectCounter = connect(
    //   mapStatetoProps
    // )(Counter)
    
    // 使用actions派发动作
    let ConnectCounter = connect(
      mapStatetoProps,
      actions
    )(Counter)
    // 定义路由
    app.router((history, app) => (
      <div>
        <ConnectCounter />
      </div>
    ))
    // 启动程序
    app.start('#root')
    
    • 启动项目,就能看到效果了

    总结

    以上是一个简单的dva的使用介绍,以及一个计数器的小栗子,后边再写一个todoList,用来深入的理解dva的使用和数据流

    展开全文
  • Dva最佳实践 -- 路由和页面动态加载一....这里先不谈论react-router中的 HashRouter或是 BrowserRouter,有兴趣深入了解React-Router的同学可以去看看它的官方文档和H5的history API。 直接以最简单暴力...


    作者: DocWhite白先生

    一. 路由

    1. 基本使用

    这里先不谈论react-router中的 HashRouter或是 BrowserRouter,有兴趣深入了解React-Router的同学可以去看看它的官方文档和H5的history API。
    直接以最简单暴力的方式结束在dva框架中,通过路由实现多页面的效果。

    (1)最基本的使用

    在 dva-cli创建的dva项目的 src目录中有一个router.js文件,从src/index.js文件中可以看出,从这里可以注册 dva 应用的路由规则以及与其对应的路由组件。同时注意看index.js文件, dva使用的model默认情况是需要在src/index.js中注册,这两点很关键。
    所以假设我们需要完成多个页面,则每个页面的路由规则和路由组件都必须要在这个src/router.js文件中注册。下面就是最常用的一种使用方式。

    在这里插入图片描述

    经常使用这种写法的同学一定知道这种写法在页面比较多的时候写起来有点繁琐,同时页面所需要的model需要单独在 src/index.js中引入。一旦web应用里面的页面变多以及其引用的model变多,将导致 src/index.js 和 router.js需要重复很多无用代码。
    当然聪明的同学肯定相当了,router.js里面的路由注册实际上可以通过数组形式遍历输出Route组件,只需要维护存储路由信息的数组即可,如下:
    在这里插入图片描述

    这样就可以把 routes 数组单独拆分出去用一个配置文件存储,而router.js文件只需要引入这个配置文件即可。简化了很多代码。

    到这一步,肯定有同学想到,这依然没有解决model的注册问题。
    所以dva官方提供了路由页面和model的动态加载方法。

    2. 动态加载

    在使用动态加载路由和model之前,要引入 dva提供的dynamic方法,该方法用于动态的注册路由组件和model。
    但需要切记的是,该写法会导致项目打包时候产生多个js文件对应不同的页面,通常名字为1.async.js, 2.async.js 等等。
    在这里插入图片描述

    利用dva/dynamic方法即可动态的加载路由组件以及其对应的model,这样我们只需要在增加页面的时候维护routes数组即可。
    在这里面,dynamic方法对于routes元素的配置项有一个隐藏接口,可以给每一个路由配置LoadingComponent,配置完成之后,在该路由组件没有加载完成前会显示该loading组件。

    ...
    {
          name: 'xxx',
          path: '/xxx',
          LoadingComponent: Loading,
          component: () => import('./routes/xxx')
    }
    ...
    

    3. 路由的组件的高阶用法

    React-Router官方文档

    (1)Route

    代码习惯好的同学,在开始使用第三方组件或库的时候一定会养成看文档的习惯,这个习惯能帮助你快速掌握第三方组件和库的使用,这里只简单的使用Route组件的例子。
    有兴趣翻看路由组件React-Router官方文档的同学会发现Route组件暴露出来的接口有:

    • path:路径
    • exact:是否完全匹配路径才渲染
    • component: path 对应的组件
    • render: 自定义渲染
    • children:不管路径是否匹配都要渲染
    • strict:路由匹配的严格模式
    • sensitive:是否对path的大小写敏感

    光看文档中跑出来的接口或者说React组件的props,就有3中渲染方法,component、render、children。大多数人可能只会用component,这没问题,但是某些情况,我们想让特定的一组页面有一样的Layout或者给这些页面组件调用的时候注入props,使用component属性就是不能实现的,因为component接受的是一个React组件类。

    所以这时候render方法给了我们一个非常好的实现方案, 就以为特定路由页面增加指定Layout为例:
    在这里插入图片描述

    这就是使用render方法去自定义页面组件渲染规则的妙用,同时由于render方法会接收要被传入页面组件的props,所以这里实际上还可以进行props拦截,替换,当然大部分情况下不需要这么复杂的操作。
    而关于children属性的使用,请查看官方文档,这里就不做过多赘述。

    二. 无需路由的情景

    由于dva框架默认就集成了React-Router中的 HashRouter,但是在某些特定情况(如嵌入式开发,被嵌入的系统已经使用了别的框架的HashRouter,判断方法,看url在某个uri后面是否跟着 /#/ 或 #/ ),使用路由会导致被嵌入的系统无法正常工作,所以我们需要剥离掉dva默认集成的React-Router或者改为BrowserRouter。

    • 无路由
      这种情况我们需要安装 dva-no-router这个库。并且在/src/index.js中将 dva的引入改为 dva-no-router。同时src/router.js 中不再需要使用React-Router组件,只需要返回一个React页面组件即可。
      在这里插入图片描述
      在这里插入图片描述

    • 改用BrowserRouter
      改用BrowserRouter只需要给dva对象配置history,值为history中 createBrowserHistory函数的执行结果。
      在这里插入图片描述

    展开全文
  • 深刻理解Dva + 上手

    2020-01-05 20:44:40
    -- npx create-react-app <项目名> /*--typescript*/ -- yarn add dva --save ## 入口文件 index.js import dva from "dva"; import RouterView from "./router"; import createHistory from ...
      -- npx create-react-app <项目名> /*--typescript*/
    	-- yarn add dva --save
    	
    ## 入口文件 index.js
    import dva from "dva";
    import RouterView from "./router";
    import createHistory from "history/createBrowserHistory";
    import { createModel } from "./store";
    const app = dva({
      history: createHistory()//history路由
    });
    createModel(app);//Model挂载
    app.router(RouterView);
    app.start("#root");/*启动应用。#root可选,如果没有 #root 参数,
    会返回一个返回 JSX 元素的函数。*/
    
    ##动态路由 
    
    ***router/index.ts
    import React from 'react';
    import Routes from './routes';
    import RouteMap from './map';
     
    function RouterView(props: any) {
    	const routes = props.routes === undefined ? Routes : props.routes;
    	return <RouteMap routes={routes} {...props} />;
    }
    export default RouterView;
    
    ***router/map.ts
    
    import React, { Component } from "react";
    import { Router, Route, Switch, Redirect } from "dva/router";
    class RouterMap extends Component<any> {
      render() {
        const { routes, history } = this.props;
        const defaultRoute = (
          <Redirect from="/" to="/home" key={"default"} exact></Redirect>//路由重定向
        );
        return (
          <Router history={history}>
            <Switch>
              {routes
                .map((item: any, index: number) => {
                  const children = item.children === undefined ? [] : item.children;
                  const Comp = item.component;
                  return (
                    <Route
                      key={item.name}
                      path={item.path}
                      component={() => {
                        return <Comp routes={children} history={history}></Comp>;
                      }}
                    />
                  );
                })
                .concat([defaultRoute])}
            </Switch>
          </Router>
        );
      }
    }
    export default RouterMap;
    
    
    ***router/routes.ts
    export default [
     {
    	path:"*",
    	name:"*", //唯一的name属性
    	component:*,
    	//children:[] 如果有子级路由则添加children 如没有可不添加
     }
    ]
    
    ##Dva状态管理
    ***store/index.js //入口文件 
    const context = require.context("./model", false, /\.(js||tsx||ts)$/);
    const getModel = context.keys().map((key) => context(key));
    export function createModel(app) {
      return getModel.map((key) => app.model(key.default));
    }  //动态挂载到app上 不需要再手动挂载
    
    *** modle/home.js
    export default {
      namespace: "home",/*model 的命名空间,同时也是他在全局 state 上的属性,
      只能用字符串,不支持通过 . 的方式创建多层命名空间*/
      state: {
       
      },
      reducers: {
       /*以 key/value 格式定义 reducer。用于处理同步操作,
       唯一可以修改 state 的地方。 由action 触发 
       格式为 (state, action) => newState 或 [(state, action) => newState, enhancer]*/},
      effects: {
       /*effects以 key/value 格式定义 effect。用于处理异步操作和业务逻辑,不直接修改  
        state。由 action 触发,可以触发 action,可以和服务器交互,可以获取全局 state 的数据等等。
        */
      *save({ payload: todo }, { put, call }) { //promise语法糖Generator
          // 调用 saveTodoToServer,成功后触发 `add` action 保存到 state
          yield call(saveTodoToServer, todo);
          yield put({ type: 'add', payload: todo });
          //call发起异步请求 put触发reducers修改state状态值
        },
      },
      subscriptions: {
    	/*以 key/value 格式定义 subscription。subscription 是订阅,用于订阅一个数据源,
    	然后根据需要 dispatch 相应的 action。在 app.start() 时被执行,数据源可以是当前的时间
    	、服务器的 websocket 连接、keyboard 输入、geolocation 变化、history 路由变化等等。
    		*/
      }
    }
    
    
    ##Dva装饰器语法
    
    import { connect } from 'dva'
    @connect((store: any) => {
      return store
    }) //this.props dispatch dva store
    /*
     当this.props.dispatch方法存在 就可以通过 
     this.props.dispatch({type:"命名空间名称+函数名",payload:"需要传递的参数"})去派发事件了
    */
    
    
    
    
    展开全文
  • dva入门讲解

    2019-02-27 21:52:24
    理解dva跟其他技术实现的对应关系,有利于深入理解dva。 为什么要用dva? 日常react开发过程中,我们经常会遇到以下场景: 我们希望有安全的数据共享机制 我们希望数据逻辑跟视图逻辑分离,既有利于提高代码健壮性...

    dva是什么?

    DVA 是基于 redux、redux-saga 和 react-router 的轻量级前端框架及最佳实践沉淀。

    理解dva跟其他技术实现的对应关系,有利于深入理解dva。

    为什么要用dva?

    日常react开发过程中,我们经常会遇到以下场景:

    • 我们希望有安全的数据共享机制
    • 我们希望数据逻辑跟视图逻辑分离,既有利于提高代码健壮性,也易于调试。
    • 我们希望异步请求数据,并改变视图。

    这些需求,dva都满足了:

    • 通过把状态上提到 dva model 中,我们把数据逻辑从页面中抽离出来。
    • 通过 effect 优雅地处理数据生成过程中的副作用,副作用中最常见的就是异步逻辑。
    • dva model 中的数据可以注入给任意组件。

    如何使用dva?

    为什么使用dva,而不选择redux,最重要的原因是dva用法简单,可以降低团队成员的学习成本。

    相比redux,dva真的可以算非常简单,我们来看看基本概念。

    model

    其中,model 是 DVA 中最重要的概念,基本的属性如下:

    • namespace:model 的命名空间,只能用字符串。一个大型应用可能包含多个 model,通过namespace区分。
    • state:当前 model 状态的初始值,表示当前状态。
    • reducers:用于处理同步操作,可以修改 state,由 action 触发。
    • effects:用于处理异步操作(例如:与服务端交互)和业务逻辑,也是由 action 触发。但是,它不可以修改 state,要通过触发 action 调用 reducer 实现对 state 的间接操作。
    • action:是 reducers 及 effects 的触发器

    connect

    熟悉react开发的你,应该知道状态控制一直是react的一个难点。

    我们可以把子组件的 state 可以上提,由父组件来管理:

    • 子组件间接回调到父组件的 setState 的方法来改变父组件的 state;
    • 新的 state 通过 props 的形式把再次被子组件获悉。

    当然,dva给了我们另一种可能,就是把state上提到所有React子组件之上,过程类似:

    • 页面通过调用 dispatch 函数来驱动 dva model state 的改变;
    • 改变后的 dva model state通过 connect 方法注入页面。

    要达到上述效果,我们就必须想办法将React跟dva这两个平行世界关联起来,connect 粉墨登场。connect是连接dva跟React的关键,一定要重点理解。

    dva中的connect ,采用的是装饰器的写法,所谓装饰器,就是给装饰对象赋予它本来不具备的能力。connect的存在,就是为了让组件获取两样东西:model中的数据,驱动model改变的方法。

    connect 接收两个参数,做的就是这两件事:

    • mapStateToProps:获取model中的数据
    • mapDispatchToProps:驱动model改变的方法

    其中,mapStateToProps 字面含义就是把dva model中的state通过组件的props注入给组件。

    mapDispatchToProps 字面含义就是将dispatch方法通过组件的props注入给组件。使用mapDispatchToProps跟dispatch向组件注入方法,组件使用这些方法能给dva model发送消息。

    dispatch

    这里就不得不提下dispatch,dispatch 函数就是和 dva model 打交道的唯一途径。 dispatch 函数接受一个 对象 作为入参,在概念上我们称它为 action,唯一强制要包含的是 type 字段,string 类型,用来告诉 dva 我们想要干什么。

    action

    终于轮到action上台了。我们把想做的事情通过 action 描述出来,并通过 dispatch 告诉 dva model,而对这个消息的处理就是 dva 的事情了。

    reducer

    我们通过dispatch派发了action,现在问题来了,dva如何识别并执行action呢?

    这就是reducer要做的事情。

    dva model 中可以定义一个叫做 reducers 的成员用来响应 action 并修改 state。每一个 reducer 都是一个 function,action 派发后,通过 action.type 被唯一地匹配到,随后执行函数体逻辑,返回值被 dva 使用作为新的 state。state 的改变随后会被 connect 注入到组件中,触发视图改变。

    我们再回过头来看上文提到的model基本属性:

    • namespace:model 的命名空间,只能用字符串。一个大型应用可能包含多个 model,通过namespace区分。
    • state:当前 model 状态的初始值,表示当前状态。
    • reducers:用于处理同步操作,可以修改 state,由 action 触发。
    • effects:用于处理异步操作(例如:与服务端交互)和业务逻辑,也是由 action 触发。但是,它不可以修改 state,要通过触发 action 调用 reducer 实现对 state 的间接操作。
    • action:是 reducers 及 effects 的触发器

    dva的用法,其实都是围绕着这些基本属性展开,本人希望读者可以加深对这些属性的理解。

    最后,上一张dva官方的代码示例图吧:

    展开全文
  • 19年全新React教程全家桶实战redux+antd+dva+Hooks前端js视频 ...
  • React Native / React调试技巧 做过原生APP开发的同学们都清楚,我们在Xcode和studio中就可以直接对编写的代码进行断点调试,很方便,但是web开发断点调试就不能直接在开发工具中完成了,需要借助浏览器来完成,...
  • 现实中,应用往往包含很多功能,这些功能无法通过一个页面展示,所以应用往往是‘多页面应用’。而且,用户在这些页面之间来回切换,开发者要做的就是保证用户的操作顺畅。最好的解决办法就是虽然逻辑上是‘多页面...
  • React还没有了解的同学可以看看我之前的一篇文章,可以快速简单的认识一下ReactReact入门最好的实例-TodoList 自己从开始接触react一窍不通,到慢慢的似懂非懂,通过各种途径学习也有一阵了。学习过程中还会...
  • 后来越学越深入后自然也就会了hooks。并且对类组件有了另一层理解。 以前我们写类组件,都是class xxx extend React.component对吧,但是为什么写个class就能渲染到页面上?这肯定不正常啊。我们学了语法都知道class...
  • 1 早年风靡前端届的CoffeeScript是什么??? 2 ES6要抓紧学。。。。 1 react,ant-design,dva,Mock ,用dva框架
  • react获取URL中参数

    2019-05-14 11:18:27
    这个问题想必很多人都会遇到过,这里我说一下怎么获取URL中的参数。 如图获取purchaseOrderNo中的值。 这个时候我们需要使用一个东西: `queryString.parse(_this.props.location.search)` ...
  • 毫不夸张,你能看到这篇文章,是你的运气,里面都是干货,在理解js的道路上容易误解的和关键点的知识。牛逼先不吹....看内容 react redux react-redux redux-thunk中间件 es6特殊语法 闭包 作用域scope等知识等你吃...
  • model的数据: export default { namespace: 'example', //表示对于整个应用不同的命名空间,以便通过this.props.example访问,和当前model文件名相同就好之前的reducer名字相同,是全局state的属性,只能为字符...
  • 揭秘react生态体系

    2017-08-29 17:55:02
    react 的生态体系比较庞大,它在web端,移动端,服务器端,VR领域都有涉及。 react可以说是目前为止最热门,生态最完善,应用范围最广的前端框架。react结合它的整个生态,它可以横跨web端,移动端,服务器端,...
  • 一,前言学校这边的项目刚组建好开发团队,前一段时间都在考虑如何前后端分离,如何多人协作开发的问题,恰好上一周陪女朋友去承德写生,能暂时放下工作和学校的事物,有了更多的思考时间。假期期间学习了webpack,...
  • Dva.js 入门级教学文档-1简介一、介绍1、什么是 dva2、dva 的作用是什么二、环境搭建和使用1、环境搭建2、创建项目3、使用 antd三、全局架构1、index.js(重点)(1)、创建 dva 实例(2)、装载插件(3)、注册 Model(4)、...
  • JavaScript - React经典教程系列 全栈开发工程师,现职于北京...
  • 临冬之际,移动端跨平台在经历数年沉浮之后,如今还能在舞台聚光灯下雀跃的, 也只剩下 React Native 和 Flutter 了,作为沉淀了数年的 “豪门” 与 19 年当红的 “新贵” ,它们之间的 “针锋相对” 也成了开发者们...
  • 构建你的 Dva2

    2020-06-11 09:51:20
    一直是 Ant Design 的深度用户,手头有新项目,都会毫不犹豫的选择 Dva+Roadhog+Ant Design 。让我眼前一亮的是,Dva 有升级版本了。...这使得 dva 可以应用在除 react 之外的其他领域,比如 RN、小程...
1 2 3 4 5 ... 12
收藏数 238
精华内容 95
关键字:

dva深入理解 react