如何实现react+redux的升级版todoList
这篇文章主要为大家展示了“如何实现react+redux的升级版todoList”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何实现react+redux的升级版todoList”这篇文章吧。
结构
该项目使用react官方的create-react-app架构,每个目录可以根据自己的需求来划分。下面解释下每个目录的内容和功能。
public:主要放静态资源(入口html文件,图片资源,JSON文件等);
class="lazy" data-src/component:不同的组件;
class="lazy" data-src/layouts:整个页面的基本架构,主要就是Nav,Footer,Content。Nav里面显示User和Notice的数据,Content中实现页面路由的切换,Footer固定不变;
class="lazy" data-src/redux:
--class="lazy" data-src/redux/configureStore:生成整个应用的store;
--class="lazy" data-src/redux/reducers:所有reducer的集合;
class="lazy" data-src/routes:页面的整体路由;
class="lazy" data-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,在class="lazy" data-src/redux/reducers中将所有的reducer合并,并且注意每个reducer的名字要和state同名:
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放在class="lazy" data-src/views/TodoList中,其他同理,代码如下:
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:
//处理更新任务状态后和删除任务后的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时加入就行了:
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传入整个应用。
以上是“如何实现react+redux的升级版todoList”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网行业资讯频道!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341