一、简介

  本文将简单分析dva脚手架的使用及项目搭建过程。

  首先,dva是一个基于redux和redux-saga的数据流方案,然后为了简化开发体验,dva还额外内置了react-router和fetch,所以也可以理解为一个轻量级的应用框架。

二、特性

  易用易学、elm概念、插件机制、支持HMR。

三、环境搭建

1、首先安装dva-cli

npm install dva-cli -g

2、初始化项目

dva new dva-quickstart
cd dva-quickstart
npm start

3、引入antd

  通过 npm 安装 antd 和 babel-plugin-import 。babel-plugin-import 是用来按需加载 antd 的脚本和样式的.

npm install antd babel-plugin-import --save

4、按需加载,找到根目录下面的.webpackrc文件,并在文件中添加插件配置。

"extraBabelPlugins": [
["import", { "libraryName": "antd", "style": "css" }]
]

5、试引入ant 组件button

import React from 'react';
import { connect } from 'dva';
import styles from './IndexPage.css'; import { Button } from 'antd' function IndexPage() {
return (
<div className={styles.normal}>
<h1 className={styles.title}>Yay! Welcome to dva!</h1>
<Button type="primary">primary</Button>
<div className={styles.welcome} />
<ul className={styles.list}>
<li>Getting Started</li>
</ul>
</div>
);
} IndexPage.propTypes = {
}; export default connect()(IndexPage);

四、项目目录结构介绍

1、目录结构

assets目录:一般作为静态文件存储目录,比如图片或者css;

components:组件目录;

models:应用逻辑层,可存放公共的数据以及逻辑,类似于vuex;

pages(routes):页面路由存放文件夹;

services:页面API请求数据;

utils:公共方法的封装;

index.js:入口文件;

router.js:路由文件

2、具体文件介绍

2.1、index.js  入口文件

import dva from 'dva';
import './index.css'; // 1. Initialize
const app = dva(); // 2. Plugins
// app.use({}); // 3. Model
app.model(require('./models/example').default);
app.model(require('./models/todos').default); // 4. Router
app.router(require('./router').default); // 5. Start
app.start('#root');

2.2 router.js路由文件

import React from 'react';
import { Route, Switch } from 'dva/router'; import dynamic from 'dva/dynamic' // 路由按需加载
import { ConnectedRouter } from 'react-router-redux';
import App from './pages/App' function RouterConfig({ history,app }) {
const IndexPage = dynamic({
app,
component:(()=> import('./pages/IndexPage/IndexPage'))
})
const Users = dynamic({
app,
component:(()=> import('./pages/UserPage/UserPage'))
})
const List = dynamic({
app,
component:(()=> import('./pages/ListPage/ListPage'))
})
return (
<ConnectedRouter history={history}>
<App>
<Switch>
<Route path="/" exact component={IndexPage}/>
<Route path="/users" exact component={Users}></Route>
<Route path="/list" exact component={List}></Route>
</Switch>
</App>
</ConnectedRouter>
);
}

2.3 页面组件IndexPage.js

import React from 'react';
import { connect } from 'dva';
import styles from './IndexPage.css'; import { Button } from 'antd' function IndexPage() {
return (
<div className={styles.normal}>
<h1 className={styles.title}>Yay! Welcome to dva!</h1>
<Button type="primary">primary</Button>
<div className={styles.welcome} />
<ul className={styles.list}>
<li>Getting Started</li>
</ul>
</div>
);
} IndexPage.propTypes = {
}; export default connect()(IndexPage);

五、connect()方法介绍

  connect 是一个函数,绑定 State 到 View。

import { connect } from 'dva';

function mapStateToProps(state) {
return { todos: state.todos };
}
connect(mapStateToProps)(App);

  connect 方法返回的也是一个 React 组件,通常称为容器组件。因为它是原始 UI 组件的容器,即在外面包了一层 State。

  connect 方法传入的第一个参数是 mapStateToProps 函数,mapStateToProps 函数会返回一个对象,用于建立 State 到 Props 的映射关系。

六、dispatch方法

  dispatch 是一个函数方法,用来将 Action 发送给 State。

dispatch({
type: 'click-submit-button',
payload: this.form.data
})

  type:方法名;

  payload:参数

  dispatch 方法从哪里来?被 connect 的 Component 会自动在 props 中拥有 dispatch 方法。

七、model层介绍

  比较常用的model成如下

{
namespace: 'count',
state: 0,
reducers: {
add(state) { return state + 1 },
},
effects: {
*addAfter1Second(action, { call, put }) {
yield call(delay, 1000);
yield put({ type: 'add' });
},
},
}

1.namespace:命名空间;当前 Model 的名称。整个应用的 State,由多个小的 Model 的 State 以 namespace 为 key 合成

2.state:该 Model 当前的状态。数据保存在这里,直接决定了视图层的输出

3.reducers: Action 处理器,处理同步动作,用来算出最新的 State;

4.effects:Action 处理器,处理异步动作

注:函数名前边带一个*号,是一个生成器(Generator )函数,内部使用 yield 关键字,标识每一步的操作(不管是异步或同步)。

dva 提供多个 effect 函数内部的处理函数,比较常用的是 call 和 put

  call:执行异步函数

  put:发出一个 Action,类似于 dispatch

八、demo  TODOLIst  实现

1.首先在components下新建一个TodoList.js文件

import React from 'react';
class TodoList extends React.Component{
constructor(props) {
super(props);
this.state={
value:''
}
}
addTodo(e){
if (e.keyCode===13) {
const todo = e.target.value; this.props.dispatch({
type: 'todos/addTodo',
payload: todo
})
this.setState({
value: ''
})
}
}
deleteTodo(index){
this.props.dispatch({
type: 'todos/deleteTodo',
payload: index
})
}
render() {
const todoList = this.props.todoList.map((val, index) => { return <div key={index}>
<span>{val.value}</span>
<button onClick={() => this.deleteTodo(index)}>X</button>
</div>
}); let count = 0; this.props.todoList.map(item => count = !item.finished ? count + 1 : count); return (
<div>
<h3>待办事项有:{count}</h3>
<input placeholder="please input"
value={this.state.value}
onChange={(e) => this.setState({value: e.target.value})}
onKeyDown={(e) => this.addTodo(e)}/>
<div>
{todoList}
</div>
</div>
)
}
} export default TodoList;

代码中:通过dispatch 派送一个action,type为action名称,payload为传递参数

 this.props.dispatch({
type: 'todos/addTodo',
payload: todo
})

2.新建路由页面LIstPage.js

import {connect} from 'dva';
import TodoList from '../../components/TodoList'; const mapStateToProps = (state) => { return {
todoList: state.todos.todoList
}
}; export default connect(mapStateToProps)(TodoList);

通过mapStateToProps 方法将model里的todoList放回到页面组件的props.todoList;

3.新建一个model todos.js

import queryString from 'query-string';
import * as todoService from '../services/todo' export default {
namespace: 'todos',
state: {todoList: []},
reducers: {
save(state, {payload: {todoList}}) {
return {...state, todoList}
}
},
effects: {
* addTodo({payload: value}, {call, put, select}) {
// 模拟网络请求
const data = yield call(todoService.query, value);
let tempList = yield select(state => state.todos.todoList);
let todoList = [];
todoList = todoList.concat(tempList);
const tempObj = {};
tempObj.value = value;
tempObj.id = todoList.length;
todoList.push(tempObj);
yield put({type: 'save', payload: {todoList}})
},
* deleteTodo({payload: index}, {call, put, select}) {
const data = yield call(todoService.query, index);
let tempList = yield select(state => state.todos.todoList);
let todoList = [];
todoList = todoList.concat(tempList);
todoList.splice(index, 1);
yield put({type: 'save', payload: {todoList}})
},
},
subscriptions: {
setup({dispatch, history}) {
// 监听路由的变化,请求页面数据
return history.listen(({pathname, search}) => {
const query = queryString.parse(search);
let todoList = []; if (pathname === 'todos') {
dispatch({type: 'save', payload: {todoList}})
}
})
}
}
}

一般来说,effects做主要的逻辑计算,reducers做数据存储,通过复杂的逻辑计算后,把处理好的数据调用reducers的方法进行数据存储。

4.在index.js进行model以及路由注入

import dva from 'dva';
import './index.css'; // 1. Initialize
const app = dva(); // 2. Plugins
// app.use({}); // 3. Model
app.model(require('./models/example').default);
app.model(require('./models/todos').default); // 4. Router
app.router(require('./router').default); // 5. Start
app.start('#root');

dva使用及项目搭建的更多相关文章

  1. 002-and design-基于dva的基本项目搭建

    一.概述 在真实项目开发中,你可能会需要 Redux 或者 MobX 这样的数据应用框架,Ant Design React 作为一个 UI 库,可以和任何 React 生态圈内的应用框架搭配使用.我们 ...

  2. Intellij IDEA Java web 项目搭建

    Java web 项目搭建 简介 在上一节java web环境搭建中,我们配置了开发java web项目最基本的环境,现在我们将采用Spring MVC+Spring+Hibernate的架构搭建一个 ...

  3. 项目搭建系列之一:使用Maven搭建SpringMVC项目

    约定电脑都安装了eclipse,且已配置好Maven以及eclipse插件. 1.Eclipse 2.maven 3.Eclipse 需要安装maven插件.url:maven - http://do ...

  4. maven项目搭建

    一.Maven简介 Maven是基于Java平台的项目构建(mvn clean install).依赖管理(中央仓库,Nexus)和项目信息管理的项目管理工具. Maven是基于项目对象模型(POM) ...

  5. maven3常用命令、java项目搭建、web项目搭建详细图解

    http://blog.csdn.net/edward0830ly/article/details/8748986 ------------------------------maven3常用命令-- ...

  6. Java web 项目搭建

    Java web 项目搭建 简介 在上一节java web环境搭建中,我们配置了开发java web项目最基本的环境,现在我们将采用Spring MVC+Spring+Hibernate的架构搭建一个 ...

  7. requirejs + vue 项目搭建2

    上篇是年后的项目搭建的,时间比较仓促,感觉有点low 1.gulp-vue 文件对公用js的有依赖,以后别的同事拿去搭其他项目,估计会被喷 2.不支持vue-loader一样写模版语言和es6语法 最 ...

  8. requirejs + vue 项目搭建

    以前都是支持 司徒正美 的,毕竟咱们也是跟着 司徒正美 一起走进了前端的世界.所以一般MVVM都是用avalon的,当然也是考虑到项目需要支持IE6,7,8的考虑.当然在用的时候也有一些小坑和bug, ...

  9. Spirng+SpringMVC+Maven+Mybatis+MySQL项目搭建(转)

    这篇文章主要讲解使用eclipse对Spirng+SpringMVC+Maven+Mybatis+MySQL项目搭建过程,包括里面步骤和里面的配置文件如何配置等等都会详细说明. 如果还没有搭建好环境( ...

随机推荐

  1. Unix\Linux | 总结笔记 |文件系统_shell重定向

    输入重定向< 从文件中获得命令需要的输入数据,适合数据源已经定义好,可重复使用 #显示文件test.txt的内容 cat < tesxt.txt #统计文件test.txt中的行数 单词数 ...

  2. 《Windows核心编程系列》八谈谈用内核对象进行线程同步

    使用内核对象进行线程同步. 前面我们介绍了用户模式下线程同步的几种方式.在用户模式下进行线程同步的最大好处就是速度非常快.因此当需要使用线程同步时用户模式下的线程同步是首选. 但是用户模式下的线程同步 ...

  3. CF446C [DZY loves Fibonacci]

    Description Transmission Gate 你需要维护一个长度为\(n \leq 300000\) 的数列,兹词两个操作: 1.给一个区间加上一个fibonacci数列,规定\(f[0 ...

  4. [CF997E] Good SubSegment

    Description Transmission Gate 给你一个长度为n的排列P,定义一段子区间是好的,当且仅当这个子区间内的值构成了连续的一段.例如对于排列\(\{1,3,2\}\),\([1, ...

  5. bitset优化背包问题

    https://blog.csdn.net/HowardEmily/article/details/77340566 留坑待填

  6. 链表中用标兵结点简化代码 分类: c/c++ 2014-09-29 23:10 475人阅读 评论(0) 收藏

    标兵结点(头结点)是在链表中的第一个结点,不存放数据,仅仅是个标记 利用标兵结点可以简化代码.下面实现双向链表中的按值删除元素的函数,分别实现 带标兵结点和不带标兵结点两版本,对比可见标兵结点的好处. ...

  7. Service官方教程(5)后台服务发送通知、把服务变前台服务。

    1.Sending Notifications to the User (发送通知) Once running, a service can notify the user of events usi ...

  8. 最简单的struts实例介绍

    struts2环境配置   struts2框架,大多数框架都在使用.由于工作需要,开始做Java项目.先学个struts2. 一.下载struts2 有好多版本,我下载的是struts-2.2.1.1 ...

  9. 前台js获得json数据

    $.ajax({ type:"post", url:"testAction.action", data:{ classId:classId }, success ...

  10. actuator服务实战

    1. actuator服务实战 1.1. 前言 actuator默认集成了很多端点查看,这里我会挑选也用到可能性大些的 1.2. Endpoints 1.2.1. 使用方式 开启服务后,直接访问:lo ...