2018-01-25 17:35:24 u011486491 阅读数 1087

Dva基础学习

参考:

https://github.com/dvajs/dva/blob/master/docs/API_zh-CN.md

 

什么是dva:

基于 redux、redux-saga 和 react-router 的轻量级前端框架

但是它解决了因为 redux带来的文件多,流程复杂的问题。

他最核心的是提供了 app.model 方法,用于把 reducer, initialState, action, saga 封装到一起

代码展示

model代码展示


使用展示

API

app = dva(opts)

创建应用,返回 dva 实例。

可配置的opts如下:

const app = dva({

  history,

 initialState,

 onError,

 onAction,

 onStateChange,

 onReducer,

 onEffect,

 onHmr,

 extraReducers,

 extraEnhancers,

});

 

 

app.use(hooks)

配置 hooks 或者注册插件。

 

 

app.model(model)

注册 model

 

 

app.unmodel(namespace)

取消 model 注册,清理 reducers, effects 和 subscriptions。

 

 

app.router(({ history, app }) => RouterConfig)

注册路由表。

 

 

app.start(selector?)

启动应用。selector 可选,如果没有 selector 参数,会返回一个返回 JSX 元素的函数。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2019-11-05 18:41:31 qq_41609775 阅读数 11

1. config文件单独打包

  1. 在前端项目根目录建立文件webpack.config.js ,若存在,则在里面修改代码。
  2. webpack.config.js里面代码如下。
let webpack = require('webpack');
let path = require('path');

export default function (config, env) {
	Object.assign(config.entry, {
	//kpiCheckConfig 换成自己项目中的配置文件 
  	'config': ['./src/config/kpiCheckConfig.js'],
})

config.plugins.push(new webpack.optimize.CommonsChunkPlugin({ 
  	name: 'config', // 这公共代码的chunk名为'config'
  	filename: 'config.js', // 生成后的文件名
  	minChunks: Infinity
}))

return config
}

2. 前端打包优化(使用webpackdll插件)

当项目的前端文件越来越多时,由于选用的框架版本 ( 主要是指 dva、roadhog ) 过于陈旧,会导致打包速度越来越慢,动辄十几分钟,到最后会导致内存溢出,打包失败,需要使用下面的 webpack 的 dllplugin 插件解决打包问题。

熟悉 Windows 的朋友就应该知道,DLL 所代表的含义。在 Windows 中有大量的 .dll 文件,称为动态链接
库。在我们的项目中,要做的也是将各个模块中公用的部分给打包成为一个公用的模块。这个模块就包含了
其他模块中需要的函数和数据(比如:其他组件所需的 React和dva 库等)。

使用 DllPlugin 的时候,会生成一个 manifest.json 这个文件,所存储的就是各个模块和所需公用模块的对应
关系。

  1. 根据各自项目依赖生成对应的 manifest.json 文件
    以下步骤只需要操作一次,生成完公共依赖包后,即可删掉新增的配置文件和相关配置( 过河拆桥 )。
  • 新建一个生成 dll 的配置文件: webpack.dll.config.js ,
const webpack = require('webpack')
module.exports = {
  	entry: {
    	bundle: [
	  	  'react',
		  'react-dom',
		  'react-router',
		  'dva',
		  'moment',
		  'antd'
      	  //其他需要单独打出的公共库
    	],
 	},
  	output: {
	    path: './public',
	    filename: 'commons.js',
	    library: 'commons_library',
 	 },
	plugins: [
	    new webpack.DllPlugin({
	       path: './public/commons.manifest.json',
	       name: 'commons_library',
	  }),
//查看打包过后的文件组成, 发现moment的其它几十种语言包占用了大量空间, 我们的项目只需要保留中英文及可
   new webpack.IgnorePlugin(/^\.\/(?!zh-cn|en-gb)/, /moment[\/\\]locale$/), 
 ],
}
  • 在 package.json 文件里,加以下运行命令:
"webpackdll": "webpack --config webpack.dll.config.js"
  • 运行如下命令生成 commons.js 及 commons.manifest.json 文件( 在public目录下 )。
npm run webpackdll
  1. 在 webpack.config.js 中添加插件,依赖生成的公共文件
config.plugins.push(new webpack.DllReferencePlugin({ 
	context: '.',
	manifest: require("./public/commons.manifest.json"), 
}),)

如果已经把 antd 打包在公共文件里, 就需要在 .roadhogrc 文件里删掉 antd 的按需加载,只保留 ewec 的按需加载,通过查看打包生成的文件结构,发现每个chunk都包含了整个的antd,导致文件过大内存溢出,取消antd的按需加载,大大减小了打包过后的文件体积,提高了打包及浏览器加载速度。

删掉

{
	"libraryName": "antd",
	"libraryDirectory": "lib",
	"style": true
},
  1. 取消 antd 的按需加载之后, 就需要把 antd 的整个样式文件复制到 public 文件夹中, 然后直接挂载到 index.html 中, 顺序如下:
//antd的样式文件位于 node_modules\antd\dist\antd.css, 也可直接复制压缩版本 antd.min.css 
<link rel="stylesheet" href="/antd.css" />
<link rel="stylesheet" href="/index.css" />
  1. 在 index.html 中手动添加 commons.js 依赖,顺序如下:
<script src="/config.js"></script>
<script src="/commons.js"></script>
<script src="/index.js"></script>

以上所有配置修改完成, 就可正常打包了

需要提交到 gitlab 的新文件有 public 下的 antd.css 、 commons.js和commons.manifest.json, 需要更新到 gitlab 的旧文件有 webpack.config.js 和 index.html。

3. 升级roadhog 版本解决前端打包缓存问题

升级完成后,需要联系运维修改前端部署配置,之前,运维是直接修改 config.js 里面的URL路径配置,需要改成修改以 config 开头的 JS 文件,例如 config.lkjsdf42545.js 里面的URL路径。

由于前端项目所采用的打包工具版本较老 (roadhog: 0.X.X) ,打包出来的文件名字统一为 1.1.js,2.2.js……,或者其它固定的名字,这样代码更新发布之后,用户的浏览器还是会从缓存取 JS,CSS 文件, 导致新的功能出不来,或者报错,严重影响客户使用。

roadhog 1.X 版本支持 hash 文件名配置, 编译后生成的文件如果内容有变化,会生成不同的文件名,这样就解决了缓存问题。roadhog 最新版本为 2.X,如果升级到 2.X ,需要对代码进行修改,影响范围较大,所以老项目升级到 1.X ,新的前端项目建议直接使用 2.X,热部署和打包编译速度会有很大提升。

下面进入简单的改造流程:

  1. 修改 roadhog 的依赖版本
"roadhog": "^1.2.2"
  1. 添加 hash 配置
  • 在 .roadhogrc 里添加 hash 配置,使打包出来的普通文件( JS 和 CSS )带上 hash 码
"hash": true
  • 修改单独打包的 config.js 文件名,加上 hash 码:
filename: 'config.[hash:7].js', // 生成带hash的config文件
  • 3.由于生成的 JS 文件和 CSS 文件都带有 hash 码了,public/index.html 里面写死的文件引入肯定就会有问题,删掉它,在 src 下建一个 ejs 模板文件, roadhog 1.X 会默认找 src 根目录下的 index.ejs 文件,自动在里面引入 JS 和 CSS ,并生成需要的 index.html。
    index.js 代码如下:
    如果项目上有额外的 JS,CSS 引用,直接在 index.js 里面添加即可
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1"> <title></title>
	</head>
	<body>
		<div id="root"></div>
	</body>
</html>

4.使用umi ,替换roadhog

4.1. 介绍

umi 是蚂蚁金服的底层前端框架,已直接或间接地服务了 600+ 应用,包括 java 、 node 、 H5 无线、离线
(Hybrid )应用、纯前端 assets 应用、 CMS 应用等。他已经很好地服务了我们的内部用户,同时希望他也能服务好外部用户。

4.2. 为什么使用 umi , 而不是 roadhog

  1. 这两个框架都是同一个作者, 而且该作者已经说明,工作重心在 umi 上, roadhog 的 issue 维护不太积极, 后面可能会放弃维护, 所以作者推荐使用 umi。
  2. roadhog 是比较纯粹的 webpack 封装工具,作为一个工具,他能做的就比较有限(限于 webpack
    层)。而 umi 则等于 roadhog + 路由 + HTML 生成 + 完善的插件机制,所以能在提升开发者效率方面发挥出更大的价值。并且与 dva 数据流的深入融合,支持 duck directory 、 model 的自动加载、 code splitting 等等。
  3. 使用 umi 之前, dva 项目之前通常都是这种扁平的组织方式:
+models
	-global.js
	-a1.js
	-a2.js
	-b.js
+services
	-a.js
	-b.js
+routes
	-PageA.js
	-PageB.js

用了 umi 后,可以按页面维度进行组织:

+models/global.js
+pages 
	+ a
		- index.js
		+components
			-A1.js
			-A2.js
		+models
			-a1.js
			-a2.js
		+services
			-a.js
	+b
		- index.js 
		- model.js 
		- 	service.js

好处是结构更加清晰了,减少耦合,方便阅读及查找代码,一删全删,方便 copy 和共享。
umi 的特点及使用方法(编码方式和 roadhog 版本并无二致, 只是有些配置变化和文件的路径不同)。

  1. routes 文件夹用 pages 代替, 即: routes/user/A.js -> pages/user/A.js
  2. 自动注入 model,无需手动在 router.js 里注入 model。
  3. 更少的配置文件
首先,我们的 package.json 里会少很多依赖,
dva-loading
dva-hmr
dva
react
react-dom
如果你用了 antd,那么还可以省掉
antd
antd-mobile
babel-plugin-import
然后,webpack.config.js、原 .roadhogrc.js、原 .roadhogrc.mock.js 也能大幅省略
  1. 更快的编译速度,以及热部署速度,提升开发效率。

5. 生产环境, 屏蔽代码中console.log

  1. 安装插件 babel-plugin-transform-remove-console
npm install babel-plugin-transform-remove-console --save-dev
  1. 配置 .roadhogrc
"production": {
	"extraBabelPlugins": [
		//添加下面这行代码即可, 生产环境只保留error级别的日志, log和warn级别的日志自动忽略
		["transform-remove-console", {"exclude": ["error"]}], 
		"transform-runtime",
		"dva-hmr",
		["module-resolver", { 
		"alias": {
			"@": "./src"
			}
		}],
		["import", [
			{
				"libraryName": "ewec",
				"libraryDirectory": "lib/components"
			}
		]]
	]
}
2018-11-21 09:27:37 PINGER0077 阅读数 2453

学react是会有很多疑惑,

  • 不知道需要用到ES6的哪些知识点;
  • react component 有三种写法,都要掌握还是
  • ....

JavaScript语言

变量声明

const 和 let
不要用var, 而是用const和let, 分别表示常量和变量。不同于var的函数作用域, const和let都是块级作用域

const DELAY = 1000;

let  count = 0;
count = count + 1;

模板字符串
模板字符串提供了另一种做字符串组合的方法。

const user = 'world';
console.log(`hello ${user}`);    //hello world

//多行
const content = `
    Hello ${firstName},
    Thanks for ordering ${qty} tickets to ${event}.
`;

默认参数

function  logActivity(activity = 'skiing') {
    console.log(activity);
}

logAcitity();    //skiing

箭头函数
函数的快捷写法,不需要通过function关键字创建函数,并且还可以省略return关键字。同时,箭头函数还会继承当前四昂下文的this关键字。
比如:

[1, 2, 3].map(x => x + 1)

等同于:

[1, 2, 3].map((function(x) {
    return x + 1;
}).bind(this));

模块的import和export
import用于引入模块,export用于导出模块
比如:

//引入全部
import dva from 'dva';

//引入部分
import { connect } from 'dva';
import { Link, Route } from 'dva/router';

//引入全部并作为github对象
import * as github from './service/github';

//导出默认
export default App;
//部分导出, 需import { App } from './file'; 引入
export class App extend Component {};

ES6对象和数组
析构赋值

析构赋值让我们从Object或Array里取出部分数据存为变量

//对象
const user = { name: 'guanguan', age: 2};
const { name, age } = user;
console.log(`${name} : ${age} `);        //guanguan : 2

//数组
const arr = [1, 2];
const [foo, bar] = arr;
console.log(foo);

我们也可以析构传入的函数参数

const add = (state, { payload } => {
    return state.concat(payload);
});

析构时还可以配alias(别名),让代码更具有语义

const add = (state, { payload: todo }) => {
    return state.concat(todo);
};

对象字面量改进

这是析构的反向操作,用于重新组织一个object

const name = 'duoduo';
const age = 8;

const user = { name, age };    //{ name: 'duoduo', age: 8};

定义对象方法时,还可以省去function关键字

app.model({
    reducers: {
        add() {} //等同于 add: function() {}
    },
    effects: {
        *addRemote() {}    //等同于addRemote: function*() {}
    },
});    

Spread Operator

Spread Operator即3个点...,有几种不同的使用方法
可用于组装数组。

const name = 'duoduo';
const age = 8;

const user = { name, age };    //{ name: 'duoduo', age: 8};

 也可用户获取数组的部分项

const arr = ['a', 'b', 'c'];
const [first, ...rest] = arr;
rest;    //['b', 'c']

//with ignore
const [first, , ...rest] = arr;
rest;    //['c']

 代替apply

function foo(x, y, z){}
const args = [1, 2, 3];

//下面两句效果相同
foo.apply(null, args);
foo(...args);

对于Object而言,用于组合成新的Object

const foo = {
    a: 1,
    b: 2,
};

const bar = {
    b: 3,
    c: 2
};

const d = 4;

const ret = {...foo, ...bar,d };    //{ a: 1, b: 3, c: 2, d: 4}

 promise

promise用于更优雅地处理异步请求。比如发起异步请求:

fetch('/api/todos')
    .then(res => res.json())
    .then(data => ({ data }))
    .catch(err => ({ err }));
 

定义Promise

const delay =(timeout) => {
    return new Promise(resolve => {
        setTimeout(resolve, timeout);
    });
};

delay(1000).then(_ => {
    console.log('executed');
});

Generators
dva的effects是通过generator组织的。generator返回的是迭代器,通过yield关键字实现暂停功能
这是一个典型的dva effect,通过yield把异步逻辑通过同步的方式组织起来

app.model({
    namespace: 'todos',
    effects: {
        *addRemote({ payload: todo }, { put, call }) {
            yield call(addTodo, todo);
            yield put({ type: 'add', payload: todo });
        },    
    },
});

React Component

Stateless Functional Component

react Compnent 有三种定义方式,分别是React.createClass, class和Stateless Functional Component。推荐使用最后一种,保持简洁和无状态,这是函数,不是Object,没有this作用域。

比入定义App Component

function App(props){
    function handleClick(){
        props.dispatch({ type: 'app/create' })
    }
    return <div onClick={handleClick}>${props.name}</div>
}

JSX

Component嵌套

类似HTML,JSX里可以给组件添加子组件

<App>
    <Header />
    <MainContent />
    <Footer />
</App>

className

class是保留字,所以添加样式时,需用className替代class

<h1 className = "fancy">hello dva</h1>

JavaScript表达式

javascript表达式需要用{}括起来,会执行并返回结果。

<h1>{this.props.title}</h1>

Mapping Arrays to JSX

可以把数组映射为JSX元素列表

<ul>
    { this.props.todos.map((todo, i) => <li key={i}>{todo}</li>)}
</ul>

注释

尽量别用“//”做单行注释

<h1>
    {/* multiline comment */}
    {/*
        multi
        line
        comment
    */}
    {
        //single line
    }
    Hello
</h1>

Spread Atrribute

这是JSX从ECMAScript6借鉴过来的很有用的特性,用于扩充组件props

别如:

const attrs = {
    href: 'http://example.org',
    target: '_blank',    
};
<a {...attrs}>Hello</a>

等同于

const attrs = {
    href: 'http://example.org',
    target: '_blank',    
}
<a href = {attrs.href} target = {target.target}>Hello</a>

Props

数据处理在React中是非常重要的概念之一,分别可以通过props,state和context来处理数据。而在dva中你只需要关心props

proptypes

JavaScript是弱类型语言,所以请尽量声明propTypes对props进行校验,以减少不必要的问题

function App(props) {
    return <div>{props.name}</div>;
}
App.propTypes = {
    name: React.PropTypes.string.isRequired,
};

内置的proptype有:

  • PropTypes.array
  • PropTypes.bool
  • PropTypes.func
  • PropTypes.number
  • PropTypes.object
  • PropTypes.string

往下传数据:

往上传数据:

CSS Modules

理解css Modules

一张图理解CSS Modules的工作原理

buttom class在构建之后会被重命名为ProductList_button_1FU0u.button是本地名称。而 produc'tList_button_1FU0Ou是global name。你可以用简短的描述性名字,而不需要关心命名冲突问题。

然后你要做的全部事情就是在css/less文件里写.button{...},并在组件里通过style.button来引用他。

定义全局CSS

CSS Modules默认是局部作用域的,想要声明一个全局规则,可用:global语法

.title {
    color: red;
}

:global(.title) {
    color: green;
}

然后在引用的时候:

<App className={styles.title} />         //red
<App className="title" /}                //green

className Package

在一些复杂的场景中,一个元素可能对应多个classname,而每个className又基于一些条件来决定是否出现。这时,classname这个库就非常有用。

import classnames from 'classnames';
const App = (props) => {
    const cls = classnames({
        btn: true,
        btnLarge: props.type === 'submit',
        btnSmall: props.type === 'edit',
    });
    return <div className = { cls }/>
};

这样,传入不同的type给App组件,就会返回不同的className组合:

<App type = "submit" />         //btn btnLarge
<App type = "edit" /}           //btn btnSmall

Reducer

reducer是一个函数,接受state和action,返回老的或新的state。即:(state, action)=> state.

增删改

以todos为例。

app.model({
    namespace: 'todos',
    state: [],
    reducer: {
        add(state, { payload: todo}){
            return state.concat(todo);
        },
        remove(state, { payload: id }) {
            return state.filter(todo => todo.id != id)
        },
        update(state, { payload: updateTodo }) {
            return state.map(todo => {
                if(todo.id === updatedTodo.id) {
                    return {...todo, ...updatedTodo};
                } else {
                    return todo;
                }
            });
        },
    },
});

深层嵌套的例子,应尽量避免。

Effect

app.model({
    namespace: 'todos',
    effects: {
        *addRemote({ payload: todo },{ put, call }){
            yield call(addTodo, todo);
            yield put({ type: 'add', payload: todo });
        },
    },
});

effects

put

用于触发action。

yield put({ type: 'todo/add', payload: 'Learn Dva' });

call

用于调用异步逻辑,支持promise

const result = yield call(fetch, '/todos');

select

用于从state里获取数据

const todos = yield select(state => state.todos);

错误处理

全局错误处理

dva里,effects和subscriptions的抛错全部会走onError hook,所以用在onError里统一处理错误。

const app = dva({
    onError(e, dispatch) {
        console.log(e.message);
    },
});

然后effects里的抛错和reject的promise就都会被捕获到了。

本地错误处理

如果需要对某些effects的错误进行特殊处理,需要在effect内部加 try , catch

app.model({
    effect: {
        *addRemote() {
            try{
                //your code here
            } catch(e) {
                console.log(e.message);
            }
        },
    },
});

异步请求

异步请求基于whatwg-fetch

GET和POST

import request from '../util/request';

//GET
request('/api/todos');

//POST
request('/api/todos', {
    method: 'POST',
    body: JSON.stringify({a: 1}),
});

统一错误处理

假如约定后台返回一下格式时, 做统一的错误处理

{
    status: 'error',
    message: '',
}

编辑utils/request.js,加入以下中间件。

function parseErrorMessage({ data }) {
    const { status, message } = data;
    if(status === 'error' ){
        throw new Error(message);
    }
    return { data };
}

然后,这类错误就会走到onError hook里。

Subscription

subscription是订阅,用于订阅一个数据源,然后根据需要dispatch相应的action。数据源是可以是当前的时间/服务器的websocket连接,keyboard输入,geolocation变化,history路由变化等。格式为({ dispatch, history })=> unsubscribe

异步数据初始化

比如:当用户进入/users页面时,触发action user/fetch加载用户数据。

app.model({
    subscriptions: {
        setup({ dispatch, history })=>{
            history.listen(({ pathname }) => {
                if(pathname === '/users') {
                   dispatch({
                        type: 'users/fetch',
                    });
                }
            });
        },
    },
});

path-to-regexp Package

如果url规则比较复杂,比如/users/:userId/search,那么匹配和userId的获取都会比较麻烦这里推荐用path-to-regexp简化这部分逻辑

import pathToRegexp from 'path-to-regexp';

// in subscription
const match = pathToRegexp('/users/:userId/search').exec(pathname);
if (match) {
  const userId = match[1];
  // dispatch action with userId
}

Router

config with JSX Element (router.js)

<Route path = "/" component = {App} />
    <Route path = "accounts" component = {Accounts} />
    <Route path = "statements" compnent = {Statements} />
</Route>

Router Components

Route Components 是指 ./src/routes/目录下的文件,他们是./src/router.js里匹配

通过connect绑定数据

import { connect } from 'dva';
function App() {}

function mapStateToProps(state, ownProps) {
    return {
        users: state.users,
    };
}
export default connect(mapStateToProps)(App);

然后在App里就有了dispatch和users两个属性

injected Props(e.g.location)

Route Compotent 会有额外的props用以获得路由信息

  • location
  • params

基于action进行页面跳转

import { routerRedux } from 'dva/router';

//Inside Effects
yield put(routerRedux.push('/logout'));

//Out Effects
dispatch(routerRedux.push('/logout'));

//with query
routerRedux.push({
    pathname: '/logout',
    query: {
        page: 2,
    },
});

除push(location) 外还有更多方法

dva配置

Redux Middleware

比如要添加redux-logger中间件:

import createLogger from 'redux-logger';

const app = dva({
    onAction: createLogger(),
});

注:onAction支持数组,可同时传入多个中间件

history

切换history为browserHistory

import { browserHistory } from 'dva/router';
const app = dva({
    history: browserHistory,
});

去除hashHistory下的_k查询参数

import { useRouterHistory } from 'dva/router';
import { createHashHistory } from 'history';
const app = dva({
    history: userRouterHistory(createHashHistory)({querykey: false}),
});

工具

通过dva-cli创建项目

先安装dva-cli

$ npm install dva-cli -g

然后创建项目

$ dva new myapp

最后,进入目录并启动

$ cd myapp
$ npm start

 

 

 

 

 

2019-12-12 18:26:16 weixin_45416217 阅读数 341

这里是基础 其他的页面交互都建立在数据交互之上 不详细的可私信一起探讨交流

1、 需求:

后台给一个接口,获取相应的数据之后进行跳转到一个对应页面

2、使用的是dva的脚手架新建的项目

  • 目录结构
  • 在 dva 中,通常需要 connect Model的组件都是 Route Components,组织在/routes/目录下,而/components/目录下则是纯组件(Presentational Components)。
  • 简单来说,就是routes放需要进行数据交互的组件,components放公共组件。
  • 添加样式:
    CSS Modules会给组件的className加上hash字符串,来保证className仅对引用了样式的组件有效,如styles.normal可能会输出为normal___39QwY。
    className的输出格式可以通过webpack.config进行修改。
    在这里插入图片描述

在这里插入图片描述
3、首先拿到一个接口,需要在/services/api.js进行传入,

  • 情况一 不需要给后台返回任何参数
import request from '../utils/request';
import networkUtils from '../utils/networkUtils';
export async function inquireAccountDetailSelfIdCard() { //inquireAccountDetailSelfIdCard 为方法名
    return request(networkUtils.getAction('inquireAccountDetailSelfIdCard'), {
    //inquireAccountDetailSelfIdCard 为接口名 一般这两者可设置为相同
        method: 'POST',
        body: networkUtils.getRequestBody({}),
      });
}
  • 当需要给接口返回参数的时候
export async function 方法名 (payload在这里定义一个参数名字) {
  return request(networkUtils.getAction('接口名'), {
    method: 'POST',
    body: networkUtils.getRequestBody(payload),
  });
}

在这里插入图片描述
4、在/models/jumpPage.js 中请求接口数据
这里需要注意的是 需要在index.js 中使用

// 3. Model
app.model(require('./models/jumpPage').default);
//引入接口
import { inquireAccountDetailSelfIdCard } from '../services/api';
export default {
    namespace: 'jumpPage',
    state: {
    	//这里是需要存储从接口获取的数据 以获取数组为例
    	 dataList: [],
    },
    effects: {
    // 情况一 不要参数返回
        *handleGetSelfid({ payload }, { call, put }) {
            // 请求数据接口
            const response = yield call(inquireAccountDetailSelfIdCard);
            yield put({
                type: 'saveState',
                payload: response.datas[0],  
                //取得从接口中返回的数据中自己想要的数据值
            });
        }
        // 情况二  需要给接口返回数据
      *getApplicationPageList({ payload }, { call, put }) {
      	const response = yield call( inquireApplyMemberPageListRSTenant, payload 这里写参数);
      	yield put({
       	 type: 'getApplyPageList',
       	 payload: response.datas,
      });
    },
    },
    
// 进行数据处理
    reducers: {
        saveState(state, {payload}){
            return {
                ...state, 
                //将获取的数据存入定义的初始数组中
                dataList: payload.dataList,
            };
        },
    
    },
}

5、在/routes/JumpPage.js 中调用modelsnamespace中定义方法并获取数据

import React, { Component } from 'react';
import { connect } from 'dva';
import { Spin } from 'antd';
import  styles from './JumpPage.css';
import { message } from 'antd';

//绑定models的namespace到本组件中
@connect(({ jumpPage }) => ({
    jumpPage,
  }))

export  default class JumpPage extends Component {
    constructor(props) {
        super(props);
        this.state = {};
    }
    componentDidMount() {
        const { dispatch } = this.props;
        dispatch({
            type: 'jumpPage/handleGetSelfid',
            payload: {
                
            },
        }
        ).then(() => {
        //从models 中的jumpPage得到的数据获取idCardNo的值
            const { jumpPage:{idCardNo} } = this.props;
            //获取当前url
            var  url = window.location.href;
            if (idCardNo !== "") {
                window.location.href=`http://www.jxeduyun.com/App.ResourceCloud/Src/index.php?app=changyan&mod=ThirdpartyLogin&act=autoLoginForCityNew&refType=1391&key=token&value${idCardNo}&validateUrl&url=${url}`;
            } else {
                message.error("身份证号码为空");
            }
        })
    }
    
    render() {
        return (
            <div>
                {/* <h1 className={styles.txt}>Loading...... </h1>  */}
                <div className={styles.spin}>
                    <Spin  size="large"/>
                </div>
            </div>
        );
    }
}

6、一切以官方为主
附上链接Dva.js

2019-06-11 10:05:47 lynnwonder6 阅读数 118

References:

dva框架的使用详解及Demo教程

Dva 是什么

初识 Dva

关于dva框架的简单操作以及demo

结合官方文档:

此处不再赘述dva项目初始化的5个api(const  myapp=dva()/plugins(dva-loading)/model(require)/router/start)

  • 简述dva框架快速上手建立一个简单页面:
  1. 编写UI组件:components/ProductList.js
  2. 定义路由routes/Products.js,添加路由信息到路由表routes/router.js
  3. 定义model:models/products.js处理数据和逻辑
  4. connect UI组件和容器组件:重新编辑routes/Products.js,包括使用connect 定义异步方法dispatch action

有关于dva框架的使用:(入口文件的配置,五个关键api)
1. Initialize

const myApp = dva({
  initialState: window.INITIAL_STATE,
  history: createBrowserHistory(),
  onAction: middleware, // 注册 redux 中间件
  onError(e) {
    console.log(e.message);
  },
});

 2. Plugins  配置插件或则dva hooks(dva提供了丰富的插件的一种处理loading状态)

myApp.use(createLoading());

dva-loading的使用 :dva-loading 实践用法
3. Model  注册model:Model 数据逻辑处理,数据流动的地方。

app.model(require('./models/example').default);

关于多个models的使用:

参考了:dva学习---多个model的注册简写

models文件夹下新建index.js:

const context = require.context('./', false, /\.js$/); //这里的false表示不遍历子目录
export default context
  .keys()  //object.keys()返回所有可枚举属性
  .filter(item => item !== './index.js') //过滤掉当前的index.js
  .map(key => context(key)); //获取所有的key值包含到context中

入口文件中:

import models from './models/index'
[...models].forEach(model => app.model(model.default||model))// 用的箭头函数哦

ok了。其他参考:webpack中require.context的作用(简化import)

 

4. Router

app.router(require('./router').default);

5. Start

app.start('#root');

curd_demo的建立全流程:

简介:CURD操作

CURD是一个数据库技术中的缩写词,一般的项目开发的各种参数的基本功能都是CURD。它代表
创建(Create) 、 更新(Update) 、 读取(Read) 和 删除(Delete) 操作。CURD 定义了用于处

理数据的基本原子操作。

1.整理需求
2.确认前后端交互
3.添加model:
5个属性:
namespace:命名空间(重要)

model 的命名空间,同时也是他在全局 state 上的属性,只能用字符串,我们发送在发送 action 到相应的 reducer 时,就会需要用到namespace 。

同时用effect副作用获取state值的时候也会用到命名空间:(todo就是命名空间)

     const tempList=yield select(state=>state.todo.list);


state:初始值 

优先级比在dva中初始化时的优先级低,但是项目中基本上初始的state值均在这里定义。
reducers:对象(用于处理同步操作。等同于 redux 里的 reducer,唯一可以修改 state 的地方,
由 action 触发。)

    setItemList(state, { payload = {} }) {
      const {
        items, pageNum, totalCount, id,
      } = payload;
      return {
        ...state,
        itemList: items,
        id,
        pagination: {
          current: pageNum,
          total: totalCount,
        },
      };
    },


effects:对象(用于处理异步操作和业务逻辑。不直接修改 state。由 action 触发,可以触发 action,
可以和服务器交互,可以获取全局 state 的数据。)

   *fetchItemList({ payload = {} }, { call, put }) {
      //下面的fetchItemList方法是异步调数据的方法
      //call:执行异步函数
      //put:发出一个 Action,类似于 dispatch
      const { data = {} } = yield call(fetchItemList, { body: payload });
      yield put({ type: 'setItemList', payload: data || {} });
    },

 

 dva框架中的effects 模块的设计思想来源于 redux-saga 框架:

redux-saga框架使用详解及Demo教程

redux-saga时管理redux应用异步操作的中间件,通过创建sagas将所有的异步操作逻辑收集在一个地方集中处理,可以用来代替redux-thunk中间件。

下面只介绍几个常用的redux-saga中创建effect的函数:

  • select(selector, ...args):指示 middleware调用提供的选择器获取Store上的state数据,你也可以简单的把它理解为redux框架中获取store上的 state数据一样的功能 :store.getState()
     const tempList=yield select(state=>state.todo.list);
  • call(fn, ...args):就是可以调用其他函数的函数,它命令 middleware 来调用fn 函数, args为函数的参数,注意: fn 函数可以是一个 Generator 函数,也可以是一个返回 Promise 的普通函数,call 函数也是阻塞 effect。(一般在这里调后端数据)
     const {data={}}=yield call(todoService.query,value);
  • put(action):用来发送action的 effect,你可以简单的把它理解成为redux框架中的dispatch函数,当put一个action后,reducer中就会计算新的state并返回,注意: put 也是阻塞 effect
  •  yield put({type:'save',payload:{list}})

     

 

subscriptions:用于订阅一个数据源,然后根据需要 dispatch 相应的 action,数据源可以是当前的时间、location 变化、history 路由变化等。
4.添加组件:(UI组件)
通过props承接并且展示数据
5.添加路由:把组件挂载到路由上,这样我们在访问路由时,组件才会渲染到页面上。
配置路由表固定方式-->react-router-config使用:React Router Config(能让你像使用vue-router一样使用react-router)
6.关联组件:UI组件和容器组件,把UI组件生成容器组件(React-Redux 规定,所有的 UI (dumb)组件都由用户提供,容器组件(smart)则是由 React-Redux 自动生成。也就是说,
用户负责视觉层,状态管理则是全部交给它。)
7.请求服务端数据:componentDidMount中请求服务端数据
 完整的过程是这样的:通过在组件中 dispatch action 触发 effect,
 在 effect 中调用 service 中的方法请求接口,拿到响应数据后再触发 action,
 reducer 完成对 state 的修改。因为在 Step6 中,我们关联了组件和 Model,(mapStateToProps)
 因此当 state 变化是,新的 state 会作为组件的 props 传递给组件,从而重新渲染。

补:dva+react-router-config简单demo:(已经实现计数器以及todolist功能)

https://github.com/LynnWonder/dva-react-counter.git

react-router-config使用:

dva项目入口文件中初始化时引入app.router(require('./routes/index'));

routes/index.js配置路由,根组件放入一个空的组件<----传入routes路由表(routes/config.js)

routes/config.js类似于vue-router一样配置路由表,可以嵌套,可以引入react-router的Redirect重定向

父组件中渲染路由:(是config.js里面定义的父组件,注意和我说的空根组件区分,不然页面出现两个父组件哦~)

{renderRoutes(this.props.route.routes)}

 

dva

阅读数 1237

没有更多推荐了,返回首页