使用dva@2和antd构建todo应用

dva是基于redux,react-router,react-saga做的一层轻量封装,简化了redux中的action,reducer,store的配置,router的初始化,以及saga中的异步action处理,将上述的这些东西都统一在model中集中处理,使用起来非常方便;
使用dva脚手架需要你对redux,react-redux,redux-saga有一定的了解;

本文将通过一个todo应用的例子来呈现dva@2版本结合antd的使用,git地址:dva-2-todo,如果对你有帮助,请给个star,谢谢;

1.首先安装dva-cli

npm install dva-cli@next -g
dva -v
dva-cli version 1.0.0-bea.2

2.创建应用

dva new todo
cd todo
npm install
npm start

浏览器打开http://localhost:8000,应该能看到dva的欢迎页面;

3.生成todo路由

新建 src/pages/todo/page.js,代码如下:

export default () => (
    
todo
)

创建成功后打开http://localhost:8000/todo,会看到todo的输出;

4.创建todo应用的model

新增src/pages/todo/models/todo.js:


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

export default {
    namespace: 'todo',
    state: {
        todos: [],
        filter: null
    },
    reducers: {
        save(state, { payload }) {
            return {
                ...state,
                todos: [
                    ...state.todos,
                    payload
                ]
            }
        },
        toggle(state, { payload }) {
            return {
                ...state,
                todos: state.todos.map(t => {
                    if(t.id === payload){
                        t.completed = !t.completed;
                    }
                    return t;
                })
            }
        },
        remove(state, { payload }) {
            return {
                ...state,
                todos: state.todos.filter(t => t.id !== payload)
            }
        },
        setFilter(state, { payload }) {
            return {
                ...state,
                filter: payload
            }
        }
    },
    effects: {
        *add({ payload }, { call, put }) {
            yield call(delay, 500);
            yield put({
                type: 'save',
                payload
            })
        }
    },
    subscriptions: {
        setup({ dispatch, history }) {
            return history.listen(({ pathname, query }) => {
                if(pathname === "/todo") {
                    dispatch({
                        type: 'setFilter',
                        payload: query.filter || 'ALL'
                    })
                }
            })
        }
    }
}

namespace是当前model的命名空间,如要在组件内派发save类型的action,则action.type的值为"todo/save";
state字段为todo应用的初始state,todos为所有todo事项的集合,filter为过滤类型,分为'ALL','ACTIVE','COMPLETED'三种;
reducers里是处理不同action的reducer函数;
effects里是处理异步请求的函数,这里我们通过delay函数来模拟一个网络请求;
subscriptions用于订阅一个数据源,然后根据情况派发action,在这个例子中,监听浏览器路径,当进入todo后, 派发过滤的action;
此时在Redux开发者工具中就能看到todo的state:


使用dva@2和antd构建todo应用_第1张图片

5.创建UI组件

在src/pages/todo/components下,创建todo.js
todo.js:

import { connect } from 'dva';
import AddTodo from "./addTodo";
import TOdoList from "./todoList";
import Filter from "./filter";

function Todo(props) {
    const {todos, filter} = props
    return (
        
) } function getVisibleTodos(todos, filter) { switch(filter) { case 'ALL': return todos; case 'ACTIVE': return todos.filter(t => !t.completed); case 'COMPLETED': return todos.filter(t => t.completed); default: return todos; } } const mapStateToProps = ({todo}) => { return { ...todo, todos: getVisibleTodos(todo.todos, todo.filter) } } export default connect(mapStateToProps)(Todo);

todo.js中包括AddTodo,TodoList,Fliter三个组件,分别创建这三个js
addTodo.js:

import { connect } from 'dva';
import { Form, Input, Button } from "antd";
const FormItem = Form.Item;
let id = 0;

function addTodo(props) {

    function handleSubmit(e) {
        e.preventDefault();
        props.form.validateFields((err, values) => {
            if (!err) {
              props.dispatch({
                  type: 'todo/add',
                  payload: {
                    id,
                    text: values.todo,
                    completed: false
                  }
              });
              id++;

              // reset form
              props.form.resetFields();
            }
        });
    };

    const { getFieldDecorator } = props.form;

    return (
        
{getFieldDecorator('todo', { rules: [{ required: true, message: 'Please input todo item!' }], })( )}
) } const mapStateToProps = ({todo}) => { return { todo } } export default connect(mapStateToProps)(Form.create()(addTodo));

todoList.js:

import { connect } from 'dva';
import { List } from "antd";

function todoList(props) {

    const { todos, dispatch } = props;

    function handleToggle(id) {
        dispatch({
            type: 'todo/toggle',
            payload: id
        })
    }

    function renderItem(item) {
        return (
             handleToggle(item.id)}>toogle, delete]}>
                
{item.text} - {item.completed ? "已完成" : "未完成"}
) } return ( Todos:} dataSource={todos} renderItem={renderItem} > ) } export default connect()(todoList);

filter.js:

import { connect } from 'dva';

function filter(props) {
    const { filter, dispatch } = props;

    function handleChange(_filter) {
        dispatch({
            type: 'todo/setFilter',
            payload: _filter
        })
    }

    function addFilterItem(_filter, text) {
        if(_filter === filter){
            return text;
        }

        return (
             { handleChange(_filter) }}>{text}
        )
    }

    return (
        
SHOW: {' '} { addFilterItem("ALL", "SHOW_ALL") } {' | '} { addFilterItem("ACTIVE", "SHOW_ACTIVE") } {' | '} { addFilterItem("COMPLETED", "SHOW_COMPLETED") }
) } export default connect()(filter);

6.处理loading

现在todolist的基本功能已经实现,由于添加todo是模拟异步fetch请求,所以接下来处理一下loading状态;
修改src/pages/todo/models/todo.js,具体参考这个commit;

ok,现在这个todo应用已经搞定了,在经过redux里一堆action,reducer难以组织的摧残之后,dva不要太好用,哈哈。
如果有问题,可以联系微信:duwenbin0316

你可能感兴趣的:(使用dva@2和antd构建todo应用)