效果图
这几天在看dvaJS,dva 首先是一个基于 redux和 redux-saga的数据流方案,然后为了简化开发体验,dva 还额外内置了 react-router和 fetch,所以也可以理解为一个轻量级的应用框架。
要想学好dva你要对ES6有一些了解,对React有些了解,上手的时候就比较容易。
写这个todolist首先得安装dva-cli
通过npm安装dva-cli
npm install dva-cli -g
安装完成后输入dva -v查看版本号
创建新应用
安装完dva-cli后,可以在命令行访问到dva命令
通过dva new dva-quickstart创建新应用
这会创建dva-quickstart目录,包含项目初始化目录和文件,并提供开发服务器、构建脚本、数据mock服务、代理服务器等功能。
然后我们cd进入dva-quickstart目录,并启动开发服务器
cd dva-quickstart
npm start
components模块
add.js
import React, { Component } from 'react' import { Form, Input, Button, Select } from 'antd' import { connect } from 'dva' import styles from './input.css' const { Option } = Select; class Add extends Component { render() { const { getFieldDecorator } = this.props.form return ( <div> <Form onSubmit={this.handleAdd} className={styles.form}> <Form.Item label="姓名" className={styles.formItem}> {getFieldDecorator('name', { rules: [ { required: true, message: '不能为空' }, { pattern: /^[u4E00-u9FA5uf900-ufa2d·s]{2,20}$/, message: '输入中文名字' } ] })(<Input width='100' />)} </Form.Item> <Form.Item label="年龄" className={styles.formItem}> {getFieldDecorator('age', { rules: [ { required: true, message: '不能为空' }, { pattern: /^(?:[1-9][0-9]?|1[01][0-9]|120)$/, message: '请输入年龄' } ] })(<Input width='100' />)} </Form.Item> <Form.Item label="学历" className={styles.formItem}> {getFieldDecorator('xl', { rules: [ { required: true, message: '不能为空' } ] })( <Select style={{ 184 }}> <Option value="本科">本科</Option> <Option value="硕士">硕士</Option> <Option value="博士">博士</Option> <Option value="专科">专科</Option> </Select> )} </Form.Item> <Form.Item className={styles.formItem}> <Button htmlType="submit" type="primary">添加</Button> </Form.Item> </Form> </div> ) } handleAdd = (e) => { e.preventDefault(); this.props.form.validateFields((err, values) => { if (!err) { //与后台进行数据交互 const list = {} list.name = values.name list.age = values.age list.xl = values.xl this.props.form.setFieldsValue({ name: '', age: '', xl: '' })//点击确定让input输入框中的值为空 this.props.dispatch({ type: 'todo/add', payload: list }) } }) } } const mapStateToProps = (state) => { return { list: state.todo.list } } export default connect(mapStateToProps)(Form.create()(Add))
modify.js
import React, { Component } from 'react' import { Form, Input, Button,Select } from 'antd' import { connect } from 'dva' import styles from './input.css' const {Option} = Select class Add extends Component { render() { console.log(this.props) let { list, toIndex } = this.props const todoList = list[toIndex] const { getFieldDecorator} = this.props.form return ( <div> <Form onSubmit={this.handleUpdate} className={styles.form}> <Form.Item label="姓名" className={styles.formItem}> {getFieldDecorator('name', { initialValue:todoList.name,//设置初始的值 rules: [ { required: true, message: '不能为空' }, { pattern: /^[u4E00-u9FA5uf900-ufa2d·s]{2,20}$/, message: '输入中文名字' } ] })(<Input/>)} </Form.Item> <Form.Item label="年龄" className={styles.formItem}> {getFieldDecorator('age', { initialValue:todoList.age, rules: [ { required: true, message: '不能为空' }, { pattern: /^(?:[1-9][0-9]?|1[01][0-9]|120)$/, message: '请输入年龄' } ] })(<Input/>)} </Form.Item> <Form.Item label="学历" className={styles.formItem}> {getFieldDecorator('xl', { initialValue:todoList.xl, rules: [ { required: true, message: '不能为空' } ] })( <Select style={{ 184 }}> <Option value="本科">本科</Option> <Option value="硕士">硕士</Option> <Option value="博士">博士</Option> <Option value="专科">专科</Option> </Select> )} </Form.Item> <Form.Item className={styles.formItem}> <Button htmlType="submit" type="primary">修改</Button> </Form.Item> </Form> </div> ) } handleUpdate = (e) => { e.preventDefault(); this.props.form.validateFields((err, values) => { if (!err) { //与后台进行数据交互 const list = {} list.name = values.name list.age = values.age list.xl = values.xl this.props.form.setFieldsValue({name:'',age:'',xl:''})//点击确定让input输入框中的值为空 this.props.dispatch({ type:'todo/update', payload:list }) } }) } } const mapStateToProps = (state) => { return { list: state.todo.list, toIndex: state.todo.toIndex } } export default connect(mapStateToProps)(Form.create()(Add))
list.js
import React, { Component } from 'react' import { connect } from "dva" import { Button } from 'antd' import styles from './input.css' class List extends Component { render() { let { list } = this.props return ( <div> { list ? list.map((item, index) => ( <li key={index} className={styles.list}> <div> <span>姓名------{item.name}</span><br /> <span>年龄------{item.age}</span><br /> <span>学历------{item.xl}</span> <br /> </div> <div className={styles.btn}> <Button htmlType='submit' type='primary' onClick={() => this.handleModify(index)}>修改</Button> <Button htmlType='submit' type='danger' onClick={() => this.handleDelete(index)}>删除</Button> </div> </li> )) : '' } </div> ) } handleModify(index) { this.props.dispatch({ type: 'todo/modify', payload: index }) } handleDelete(index) { this.props.dispatch({ type: 'todo/delete', payload: index }) } } const mapStateToProps = (state) => { return { list: state.todo.list } } export default connect(mapStateToProps)(List)
routes模块(相当于pages)
input.js
import React, { Component } from 'react' import Add from "../components/add" import ListTo from './list' import Modify from "../components/modify" import {connect} from 'dva' class InputList extends Component { render() { let {flag} = this.props return ( <div> { flag? <Add/>:<Modify/> } <ListTo/> </div> ) } } const mapStateToProps=(state)=>{ return { flag:state.todo.flag } } export default connect(mapStateToProps)(InputList)
models模块
input.js
import queryString from 'query-string'; import { add } from '../services/todolist' export default { namespace: 'todo', state: { list: [], flag:true, toIndex:'' }, subscriptions: { setup({ dispatch, history }) { history.listen(location => { }) } }, effects: { *add({ payload: value }, { call, put, select }) { const data = yield call(add, value) let templist = yield select(state => state.todo.list) let list = [] list = list.concat(templist) const tempObj = {}; tempObj.name = value.name tempObj.age = value.age tempObj.xl = value.xl list.push(tempObj) yield put({ type: 'updateState', payload: { list } }) }, *delete({ payload: index }, { call, put, select }) { const data = yield call(add, index) let templist = yield select(state => state.todo.list) let list = [] list = list.concat(templist) list.splice(index, 1) yield put({ type: 'updateState', payload: { list } }) }, *modify({payload:index},{call,put,select}){ const data = yield call(add,index) let templist = yield select(state => state.todo.list) let list = [] list = list.concat(templist) yield put({ type: 'updateState', payload: { flag:false,list,toIndex:index } }) }, *update({payload:value},{call,put,select}){ const data = yield call(add,value) let templist = yield select(state => state.todo.list) let toIndex = yield select(state => state.todo.toIndex) let list = [] list = list.concat(templist) list.splice(toIndex,1,value) yield put({ type: 'updateState', payload: { flag:true,list } }) }, }, reducers: { updateState(state, action) { return { ...state, ...action.payload } } }, }
在根目录下的index.js里注册一下models
同样是在根目录下的router.js里注册路由
欢迎评论,共同交流,一起进步
源码链接:gitHub