dva.js 上手

作者: 那颗星_fcaf | 来源:发表于2018-06-13 14:20 被阅读90次

    dva.js 简介

    1. dva 是阿里前端架构师 sorrycc 带 team 研发的一套轻量级前端框架,其目的是尽量避免前端重复性劳动,简化开发流程。
      一个完整的 dva 脚手架应该包含以下内容:
      • 自动创建一个包含 package.json 的项目。
      • 自动创建成体系的目录结构。
      • 自动安装项目需要的基础包。
      • 集成代码检查工具 ESLint。
      • 集成模拟接口工具 Mock。
      • 集成服务启动打包工具 Roadhog。
      • 集成版本控制工具 Git。

    初始化

    1. 安装 dva-cli 用于初始化项目:
      npm install dva-cli -g
      
    2. 创建项目目录,并进入该目录:
      mkdir your-project  
      cd your-project
      
    3. 初始化项目:
      dva init
      
    4. 运行 npm start 运行徐项目。

    目录结构

    1. 目录初始化以后,目录默认如下:
      |- mock
      |- node_modules
      |- package.json
      |- public
      |- src
          |- asserts
          |- components
          |- models
          |- routes
          |- services
          |- utils
          |- router.js
          |- index.js
          |- index.css
      |- .editorconfig
      |- .eslintrc
      |- .gitignore
      |- .roadhogrc.mock.js
      |- .webpackrc
      
      • mock 用于存放 mock 数据的文件
      • public 一般用于存放静态文件,打包时会被直接复制到输出目录(./dist)
      • src 文件夹用于存放项目源代码
        • asserts 用于存放静态资源,打包时会经过 webpack 处理;
        • components 用于存放 React 组件,一般是该项目公用的无状态组件;
        • models 用于存放模型文件;
        • routes 用于存放需要 connect model 的路由组件;
        • services 用于存放服务文件,一般是网路请求等;
        • utils 工具类库;
        • routers.js 路由文件;
        • index.js 项目的入口文件;
        • index.css 一般是公用样式
      • .editorconfig 编辑器配置文件
      • .eslintrc ESLint配置文件
      • .gitignore Git忽略文件
      • .roadhogrc.mock.js Mock配置文件
      • .webpackrc 自定义的webpack配置文件,JSON格式,如果需要JS格式,可修改为.webpackrc.js

    antd按需引入

    1. 先安装 antdbabel-plugin-import
      npm install antd balbel-plugin-import --save
      
      babel-plugin-import 也可以通过 -D 参数安装到 devDependencies 中,它用于实现按需加载。
      之后在 .webpackrc 中添加如下配置:
      {
          "extraBabelPlugins": [
              ["import", {
                  "libraryName": "antd",
                  "libraryDirectory": "es",
                  "style": true
              }]
          ]
      }
      
      现在就可以按需引入 antd 的组件了,如: import { Button } from 'amtd'; ,Button组件的样式文件也会自动引入。
      更多.webpackrc 配置请参考 roadhog配置

    自定义 antd 主题

    1. 可以在 .webpackrc 中添加 theme 字段直接进行主题自定义,但是如果自定义的变量太多,建议单独提取出来,方便管理。

      建议在 ./src 目录下新建名为 theme.js 的文件,然后再 .webpackrc 中引入,如下:

      {
          "theme": "./src/theme.js"
      }
      

      theme.js 文件如下:

      export default {
          "primary-color": "#000",
      }
      

      更多可自定义的 antd 变量请参考 default.less

    CSS Modules

    1. 使用 dva-cli 初始化的项目默认已经启用了 CSS Modules,如果不想使用CSS Modules,在 .webpackrc 中添加一下配置即可禁用:
      "disableCSSModules": true
      

    开发代理

    1. 开发过程中如果需要代理API接口,在 webpackrc 中添加如下配置:
      {
          "proxy": {
              "/api": {
                  "target": "http://your-api-server",
                  "changeOrigin": 'true
              }
          }
      }
      

    Mock

    1. 入需 Mock 功能, 在 .webpackrc.mock.js 中配置即可,如:
      export default {
          'GET /api/users': { users: [{ username: 'admin' }] },
      }
      
      如上配置,当请求 /api/users 时会返回 JSON 格式的数据。
      同时也支持自定义函数,如下:
      export default {
          'POST /api/users': (req, res) => { res.end('OK'); },
      }
      
      具体的 API 请参考 Express.js@4.
      当 mock 数据太多是,可以拆分放到 ./mock 文件夹中,然后在 .roadhogrc.mlck.js 中引入。

    HMR

    1. HMR,即模块热替换,在修改代码后不需要刷新整个页面,方便开发时的调试。可以在 .webpackrc 中添加如下配置来使用HMR:
      {
          "env": {
              "development": {
                  "extraBabelPlugins": [
                      "dva-hmr"
                  ]
              }
          }
      }
      
      如果无效,请尝试更新一下 bebel-plugin-dva-hmr
      env 字段是针对特定环境进行配置,因为 HMR 只在开发环境下使用,所以将配置添加到 development 字段即可,运行 npm run build 时的环境变量为 production

    组件动态加载

    1. dva内置了 dynamic 方法用于实现组件的动态加载,用法如下:
      import dynamic from 'dva/dynamic';  
      
      const UserPageComponent = dynamic({
          app,
          models: () => [
              import('./models/users'),
          ],
          component: () => import('./routes/UserPage'),
      });
      
      实际使用的时候,可以对其进行简单的封装,否则每个路由组件都这么写一遍很麻烦。

    dva-loading

    1. dva-loading 是一个用于处理 loading 状态的 dva 插件,基于 dva 的管理 effects 执行的 hook 实现,它会在 state 中添加哟个 loading 字段(该字段可自定义),自动处理网络请求的状态,不需要自己再去写 showLoadinghideLoading 方法。
      ./src/index.js 中引入使用即可:
      import createLoading from 'dva-loading';
      const app = dva();
      app.use(createLoading(opts));
      
      opts 仅有一个 namespace 字段,默认为 loading

    Model

    1. Model 是 dva 最重要的部分,可以理解为 redux、react-redux、 redux-saga 的封装。

      通常一个项目中一个模块对应一个 model ,一个基本的 model 如下:

      import { fetchUsers } from '../services/user';
      
      export default {
          namespace: 'user',
          stat: {
              list: [],
          }
          reducers: {
              save(state, action) {
                  return {
                      ...state,
                      list: action.data
                  };
              },
          },
          effects: {
              * fetch(action, { put, call }) {
                  const users = yield put(fetchUsers, action.sata);
                  yield put({ type: 'save', data: users });
              },
          },
          subscriptions: {
              setup({ dispatch, history }) {
                  return history.listen(({ pathname }) => {
                      if (pathname === '/user') {
                          dispatch({
                              type: 'fetch',
                          });
                      }
                  });
              },
          },
      }
      
    • namespace 是该 model 的命名空间,同时也是全局 state 上的一个属性,只能是字符串,不支持使用 . 创建多层命名空间。

    • state 是状态的初始值。

    • reducer 类似于 redux 中的 reducer,它是一个纯函数,用于处理同步操作,是唯一可以修改 state 的地方,由 action 触发,它有 stateaction 两个参数。

    • effects 用于处理异步操作,不能直接修改 state ,由 action 触发, 也可以触发 action 。它只能是 generator 函数,并且有 actioneffects 两个参数。第二个参数 effects 包含 putcallselect 三个字段,put 用于触发 action , call 用于调用异步处理逻辑,select 用于从 state 中获取数据。

    • subscriptions 用于订阅某些数据源,并根据情况 dispatch 某些 action ,格式为 ({ dispatch, history }, done) => unlistenFunction

    如上的一个model,监听路由变化,当进入 `/user` 页面时,执行 `effects` 中的 `fetch` ,以从服务端获取用户列表,然后 `fetch` 中触发 `reducers` 中的 `save` 将从服务器获取到的数据报讯到 `state` 中。  
    
    注意,在 model 中触发这个 model 是不需要写命名空间,比如在 `fetch` 中触发 `save` 时是 `{ type: 'save' }`。而在组件中触发 `action` 时就需要带上命名空间了,比如在某个组件中触发 `fetch` 时,应该是 `{ type: 'user/fetch }`。  
    

    app

    1. ./src/index.js 中可以看到如下代码:

      import dva from 'dva';
      const app = dva();
      

      app 就是 dva 的实例,创建实例时 dva 方法传入一些参数,如下:

      • history
      • initialstate
      • onError
      • onAction
      • onStateChange
      • onReducer
      • onEffects
      • onHmr
      • extraReducers
      • extraEnhancers

      history 是给路由器用的,默认为 hashHistory ,如果想要使用 browserHistory,需要安装 history ,然后在 。/src/index.js 引入使用:

      import dva from 'dva';
      impoer createHistory from 'history/createBroeserHistory';
      const app = dva({
          history: createHistory(),
      });
      

      initialState 是 state 的初始化数据,优先级高于 model 中的state,默认为 {}
      其他以 on 开头的均为钩子函数。

    connect

    1. 当写完 moedl 和组件之后,需要将 model 和组件连接起来。 dva 提供了 connect 的方法,其实它就是 react-reduxconnect 。用法如下:
      import React from 'react';
      import { connect } from 'dva';
      
      const User = ({ dispatch, user }) => {
          return (
              <div></div>
          )
      }
      
      export default connect(({ user }) => {
          return user;
      })(User);
      
      connect 后的组件除了可以取到 dispatchstate,还可以获取到 locationhistory

    错误处理

    1. effectssubscriptions 抛出的错误都会经过 onError 钩子函数,所以可以在 onError 中进行全局错误处理。
      const app = dva({
          onError(err, dispatch) {
              console.log(err);
          },
      });
      
      如果需要对某些 effects 进行特殊的错误处理,可以使用 try catch

    异步请求

    1. dva 集成了 isomorphic-fetch 用于处理异步请求,并且使用 dva-cli 初始化的项目中,已经在 ./src/utils/request.js 中对 fetch 进行了简单的封装,可以在这里根据服务端 API 的数据结构进行统一的错误处理。

      当然,如果不想使用 fetch ,完全可以引入自己喜欢的第三方库,没有任何影响,打包时也不会将 isomorphic-fetch 打包进去。

    原文地址

    1. https://pengtikui.cn/dva.js-get-started/

    相关文章

      网友评论

        本文标题:dva.js 上手

        本文链接:https://www.haomeiwen.com/subject/rcujeftx.html