react+redux的升级版todoList的实现


Posted in Javascript onDecember 18, 2017

又是很久不写博客了,最近在用蚂蚁金服的ant-design-pro写毕设,写着写着写不下去了,很多东西都不理解,不得不说大神写出来的东西都是需要花学习成本的,或者底子好,对于React新手来说就有点难了。所以就老老实实的认真看了下Redux到底如何使用,在这里推荐一下自己最近在看的书,写的算是比较详细的:《深入React技术栈》。废话不多说,今天就分享下自己如何使用redux来实现一个todoList的,希望对想要用redux的你会有所帮助。

(为什么叫升级版呢?因为之前写过一个没有用redux的todoList)

react+redux的升级版todoList的实现

该项目使用react官方的create-react-app架构,每个目录可以根据自己的需求来划分。下面解释下每个目录的内容和功能。

public:主要放静态资源(入口html文件,图片资源,JSON文件等);

src/component:不同的组件;

src/layouts:整个页面的基本架构,主要就是Nav,Footer,Content。Nav里面显示User和Notice的数据,Content中实现页面路由的切换,Footer固定不变;

src/redux:

--src/redux/configureStore:生成整个应用的store;

--src/redux/reducers:所有reducer的集合;

src/routes:页面的整体路由;

src/utils:自己封装的工具;

views:存放项目中所要展示的所有页面;

index:整个项目的入口文件;

二. 具体实现

1. 整个应用中store中应存储什么数据?

const initialState = {
  taskListData: { //任务列表
    loading: false,
    error: false,
    taskList: [],
  }, 
  userData: { //用户信息
    loading: false,
    error: false,
    user: {},
  },
  noticeListData: { //通知列表
    loading: false,
    error: false,
    noticeList: [],
  },
  taskData: { //任务详情,在详情页使用
    loading: false,
    error: false,
    task: {},
  }
};

2. reducer的分布:

每个state对应一个reducer,所以一共需要四个reducer,在src/redux/reducers中将所有的reducer合并,并且注意每个reducer的名字要和state同名:

/*redux/reducers.js*/
import { combineReducers } from 'redux';
import userReducer from '../component/User/indexRedux';
import noticeReducer from '../component/Notice/indexRedux';
import todoListReducer from '../views/TodoList/indexRedux';
import taskReducer from '../views/Detail/indexRedux';

export default combineReducers({
  userData: userReducer,
  noticeListData: noticeReducer, 
  taskListData: todoListReducer,
  taskData: taskReducer,
});

每个state都对应一个reducer,所以和state一样,reducer应在放在最顶级的父级组件的目录中,所以将taskListData的reducer放在src/views/TodoList中,其他同理,代码如下:

/*views/TodoList/indexRedux.js*/
const taskListData = {
  loading: true,
  error: false,
  taskList: []
};
//不同的action;
const LOAD_TASKLIST = 'LOAD_TASKLIST';
const LOAD_TASKLIST_SUCCESS = 'LOAD_TASKLIST_SUCCESS';
const LOAD_TASKLIST_ERROR = 'LOAD_TASKLIST_ERROR';
const ADD_TASK = 'ADD_TASK';
const UPDATE_TASK = 'UPDATE_TASK';
const DELETE_TASK = 'DELETE_TASK';
function todoListReducer (state = { taskListData }, action) {
  switch(action.type) {
    case LOAD_TASKLIST: {
      return {
        ...state,
        loading: true,
        error: false,
      }
    }
    case LOAD_TASKLIST_SUCCESS: {
      return {
        ...state,
        loading: false,
        error: false,
        taskList: action.payload,
      };
    }
    case LOAD_TASKLIST_ERROR: {
      return {
        ...state,
        loading: false,
        error: true
      };
    }
    case UPDATE_TASK: {
      const index = state.taskList.indexOf(
        state.taskList.find(task => 
          task.id === action.payload.id));
      console.log(index);
      state.taskList[index].status = !state.taskList[index].status;
      return {
        ...state,
        taskList: state.taskList,
      };
    }
    case DELETE_TASK: {
      const index = state.taskList.indexOf(
        state.taskList.find(task => 
          task.id === action.payload.id));
      state.taskList.splice(index, 1);
      return {
        ...state,
        taskList: state.taskList,
      };
    }
    case ADD_TASK: {
      let len = state.taskList.length;
      let index = len > 0 ? len - 1 : 0;
      let lastTaskId = index !== 0 ? state.taskList[index].id : 0; 
      state.taskList.push({
        id: lastTaskId + 1,
        name: action.payload.name,
        status: false,
      });
      return {
        ...state,
        taskList: state.taskList,
      }
    } 
    default: {
      return state;
    }
  }
}
export default todoListReducer;

3. action creator的分布:

每个动作都代表一个action,action由组件发出,所以将action creator单独一个文件,放在组件目录中。例如:ListItem组件的action creator:

/*ListItem/indexRedux.js*/
//处理更新任务状态后和删除任务后的taskList的状态;
const UPDATE_TASK = 'UPDATE_TASK';
const DELETE_TASK = 'DELETE_TASK';
//action creator,更新和删除任务
export function updateTask (task) {
  return dispatch => {
    dispatch({
      type: UPDATE_TASK,
      payload: task,
    });
  }
}
export function deleteTask (task) {
  return dispatch => {
    dispatch({
      type: DELETE_TASK,
      payload: task,
    });
  }
}

三. 如何将redux和组件连接

react-redux提供了connect方法,将state和action creator绑在组件上,然后在组价内部以props的方式获取。下面是TodoList页面的具体实现:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import List from '../../component/List';
import { loadTaskList } from '../../component/List/indexRedux';
import { updateTask, deleteTask } from '../../component/ListItem/indexRedux';
import { addTask } from '../../component/SubmitDialog/indexRedux';
class TodoList extends Component {

  render () {
    return (
      <List {...this.props} />
    );
  }
}
export default connect( state => {
  return {
    loading: state.taskListData.loading,
    error: state.taskListData.error,
    taskList: state.taskListData.taskList,
  };
}, dispatch => {
  return {
    loadTaskList: bindActionCreators(loadTaskList, dispatch),
    updateTask: bindActionCreators(updateTask, dispatch),
    deleteTask: bindActionCreators(deleteTask, dispatch),
    addTask: bindActionCreators(addTask, dispatch),
  };
})(TodoList);

connect方法有四个参数,这里主要说下前两个参数:

(1)mapStateToProps:参数为state,返回页面所需要的所有state;

(2)mapDispatchToProps:参数为dispatch,返回页面所要使用的异步回调函数。

眼明手快的你肯定看到了,我们从redux包中导出了bindActionCreators方法,该方法将dispatch和action creator绑定,用来触发action。

四. 异步的action creator如何触发呢?

因为每个action creator都是异步函数,我们传给组件的只是函数的声明,所以就要引入我们的中间件,只用在生成store时加入就行了:

/*redux/configureStore.js*/
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import reducers from './reducers';
const initialState = {
  taskListData: {
    loading: false,
    error: false,
    taskList: [],
  }, 
  userData: {
    loading: false,
    error: false,
    user: {},
  },
  noticeListData: {
    loading: false,
    error: false,
    noticeList: [],
  },
  taskData: {
    loading: false,
    error: false,
    task: {},
  }
};
let enhancer = applyMiddleware(thunk);
let store = createStore(
  reducers,
  initialState,
  enhancer,
);
export default store;

在上面的代码中thunk就是一个中间件,我们将引入的中间件传入applyMiddleware就可以了。

五. store在哪里传入组件呢?

我们肯定会想到,store在整个应用中都存在,所以应该在整个应用的最顶层,对于一般项目而言,当然就是最顶端的路由了:

import React, { Component } from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import { Provider } from 'react-redux';
import BasicLayout from '../layouts';
import store from '../redux/configureStore';
class RouterApp extends Component {
  render () {
    return (
      <Provider store={store}>
        <Router>
          <Route path="/" component={BasicLayout} />
        </Router>
      </Provider>
    );
  }
}
export default RouterApp;

Provider是react-redux的一个组件,作用就是用来将store传入整个应用。

基本要讲的就是这些内容,完整的项目请看 github
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
鼠标划过实现延迟加载并隐藏层的js代码
Oct 11 Javascript
深入领悟JavaScript中的面向对象
Nov 18 Javascript
JavaScript的RequireJS库入门指南
Jul 01 Javascript
Jquery实现$.fn.extend和$.extend函数
Apr 14 Javascript
KnockoutJS 3.X API 第四章之click绑定
Oct 10 Javascript
原生js实现水平方向无缝滚动
Jan 10 Javascript
如何使用Bootstrap 按钮实例详解
Mar 29 Javascript
详解VUE 定义全局变量的几种实现方式
Jun 01 Javascript
详解react服务端渲染(同构)的方法
Sep 21 Javascript
动态统计当前输入内容的字节、字符数的实例详解
Oct 27 Javascript
浅谈js闭包理解
Mar 28 Javascript
微信小程序实现的canvas合成图片功能示例
May 03 Javascript
总结js中的一些兼容性易错的问题
Dec 18 #Javascript
详解最新vue-cli 2.9.1的webpack存在问题
Dec 16 #Javascript
HTML5+JS+JQuery+ECharts实现异步加载问题
Dec 16 #jQuery
详解如何使用 vue-cli 开发多页应用
Dec 16 #Javascript
详解VUE 数组更新
Dec 16 #Javascript
详解如何用模块化的方式写vuejs
Dec 16 #Javascript
浅谈 Vue 项目优化的方法
Dec 16 #Javascript
You might like
如何在PHP中使用Oracle数据库(6)
2006/10/09 PHP
phpMyAdmin 链接表的附加功能尚未激活的问题
2010/08/01 PHP
thinkphp的URL路由规则与配置实例
2014/11/26 PHP
PHP数组和explode函数示例总结
2015/05/08 PHP
php面向对象编程self和static的区别
2016/05/08 PHP
PHP购物车类Cart.class.php定义与用法示例
2016/07/20 PHP
Yii2.0多文件上传实例说明
2017/07/24 PHP
php实现的中秋博饼游戏之绘制骰子图案功能示例
2017/11/06 PHP
js中eval()函数和trim()去掉字符串左右空格应用
2013/02/02 Javascript
Javascript:为input设置readOnly属性(示例讲解)
2013/12/25 Javascript
javaScript中两个等于号和三个等于号之间的区别介绍
2014/06/27 Javascript
jquery 操作css样式、位置、尺寸方法汇总
2014/11/28 Javascript
JavaScript实现简单的tab选项卡切换
2016/01/05 Javascript
微信小程序 数组(增,删,改,查)等操作实例详解
2017/01/05 Javascript
jQuery实现导航回弹效果
2017/02/27 Javascript
Angular.JS去掉访问路径URL中的#号详解
2017/03/30 Javascript
Vuex之理解Getters的用法实例
2017/04/19 Javascript
vue2.0实现分页组件的实例代码
2017/06/22 Javascript
Node.js实现连接mysql数据库功能示例
2017/09/15 Javascript
javascript+html5+css3自定义弹出窗口效果
2017/10/26 Javascript
关于Vue在ie10下空白页的debug小结
2018/05/02 Javascript
vue 实现走马灯效果
2019/10/28 Javascript
微信小程序实现滑动操作代码
2020/04/23 Javascript
Python进行数据科学工作的简单入门教程
2015/04/01 Python
Python txt文件加入字典并查询的方法
2019/01/15 Python
python爬虫 urllib模块发起post请求过程解析
2019/08/20 Python
OpenCV哈里斯(Harris)角点检测的实现
2020/01/15 Python
对Matlab中共轭、转置和共轭装置的区别说明
2020/05/11 Python
Python实现读取并写入Excel文件过程解析
2020/05/27 Python
python3.9实现pyinstaller打包python文件成exe
2020/12/13 Python
咖啡为什么会有酸味?你喝到的咖啡為什麼是酸的?
2021/03/17 冲泡冲煮
HTML5 canvas 瀑布流文字效果的示例代码
2018/01/31 HTML / CSS
教师实习自我鉴定
2013/12/11 职场文书
2014年父亲节活动方案
2014/03/06 职场文书
2015共产党员公开承诺书
2015/01/22 职场文书
如何通过一篇文章了解Python中的生成器
2022/04/02 Python