react+redux的升級(jí)版todoList的實(shí)現(xiàn)
又是很久不寫博客了,最近在用螞蟻金服的ant-design-pro寫畢設(shè),寫著寫著寫不下去了,很多東西都不理解,不得不說大神寫出來的東西都是需要花學(xué)習(xí)成本的,或者底子好,對(duì)于React新手來說就有點(diǎn)難了。所以就老老實(shí)實(shí)的認(rèn)真看了下Redux到底如何使用,在這里推薦一下自己最近在看的書,寫的算是比較詳細(xì)的:《深入React技術(shù)?!?。廢話不多說,今天就分享下自己如何使用redux來實(shí)現(xiàn)一個(gè)todoList的,希望對(duì)想要用redux的你會(huì)有所幫助。
(為什么叫升級(jí)版呢?因?yàn)橹皩戇^一個(gè)沒有用redux的todoList)

該項(xiàng)目使用react官方的create-react-app架構(gòu),每個(gè)目錄可以根據(jù)自己的需求來劃分。下面解釋下每個(gè)目錄的內(nèi)容和功能。
public:主要放靜態(tài)資源(入口html文件,圖片資源,JSON文件等);
src/component:不同的組件;
src/layouts:整個(gè)頁面的基本架構(gòu),主要就是Nav,F(xiàn)ooter,Content。Nav里面顯示User和Notice的數(shù)據(jù),Content中實(shí)現(xiàn)頁面路由的切換,F(xiàn)ooter固定不變;
src/redux:
--src/redux/configureStore:生成整個(gè)應(yīng)用的store;
--src/redux/reducers:所有reducer的集合;
src/routes:頁面的整體路由;
src/utils:自己封裝的工具;
views:存放項(xiàng)目中所要展示的所有頁面;
index:整個(gè)項(xiàng)目的入口文件;
二. 具體實(shí)現(xiàn)
1. 整個(gè)應(yīng)用中store中應(yīng)存儲(chǔ)什么數(shù)據(jù)?
const initialState = {
taskListData: { //任務(wù)列表
loading: false,
error: false,
taskList: [],
},
userData: { //用戶信息
loading: false,
error: false,
user: {},
},
noticeListData: { //通知列表
loading: false,
error: false,
noticeList: [],
},
taskData: { //任務(wù)詳情,在詳情頁使用
loading: false,
error: false,
task: {},
}
};
2. reducer的分布:
每個(gè)state對(duì)應(yīng)一個(gè)reducer,所以一共需要四個(gè)reducer,在src/redux/reducers中將所有的reducer合并,并且注意每個(gè)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,
});
每個(gè)state都對(duì)應(yīng)一個(gè)reducer,所以和state一樣,reducer應(yīng)在放在最頂級(jí)的父級(jí)組件的目錄中,所以將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的分布:
每個(gè)動(dòng)作都代表一個(gè)action,action由組件發(fā)出,所以將action creator單獨(dú)一個(gè)文件,放在組件目錄中。例如:ListItem組件的action creator:
/*ListItem/indexRedux.js*/
//處理更新任務(wù)狀態(tài)后和刪除任務(wù)后的taskList的狀態(tài);
const UPDATE_TASK = 'UPDATE_TASK';
const DELETE_TASK = 'DELETE_TASK';
//action creator,更新和刪除任務(wù)
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綁在組件上,然后在組價(jià)內(nèi)部以props的方式獲取。下面是TodoList頁面的具體實(shí)現(xiàn):
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方法有四個(gè)參數(shù),這里主要說下前兩個(gè)參數(shù):
(1)mapStateToProps:參數(shù)為state,返回頁面所需要的所有state;
(2)mapDispatchToProps:參數(shù)為dispatch,返回頁面所要使用的異步回調(diào)函數(shù)。
眼明手快的你肯定看到了,我們從redux包中導(dǎo)出了bindActionCreators方法,該方法將dispatch和action creator綁定,用來觸發(fā)action。
四. 異步的action creator如何觸發(fā)呢?
因?yàn)槊總€(gè)action creator都是異步函數(shù),我們傳給組件的只是函數(shù)的聲明,所以就要引入我們的中間件,只用在生成store時(shí)加入就行了:
/*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就是一個(gè)中間件,我們將引入的中間件傳入applyMiddleware就可以了。
五. store在哪里傳入組件呢?
我們肯定會(huì)想到,store在整個(gè)應(yīng)用中都存在,所以應(yīng)該在整個(gè)應(yīng)用的最頂層,對(duì)于一般項(xiàng)目而言,當(dāng)然就是最頂端的路由了:
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的一個(gè)組件,作用就是用來將store傳入整個(gè)應(yīng)用。
基本要講的就是這些內(nèi)容,完整的項(xiàng)目請(qǐng)看 github
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
react函數(shù)組件useState異步,數(shù)據(jù)不能及時(shí)獲取到的問題
這篇文章主要介紹了react函數(shù)組件useState異步,數(shù)據(jù)不能及時(shí)獲取到的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
React如何使用axios請(qǐng)求數(shù)據(jù)并把數(shù)據(jù)渲染到組件
這篇文章主要介紹了React如何使用axios請(qǐng)求數(shù)據(jù)并把數(shù)據(jù)渲染到組件,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
react中如何使用定義數(shù)據(jù)并監(jiān)聽其值
這篇文章主要介紹了react中如何使用定義數(shù)據(jù)并監(jiān)聽其值問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
react結(jié)合bootstrap實(shí)現(xiàn)評(píng)論功能
這篇文章主要為大家詳細(xì)介紹了react結(jié)合bootstrap實(shí)現(xiàn)評(píng)論功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05
React報(bào)錯(cuò)解決之ref返回undefined或null
最近使用react做個(gè)滾動(dòng)監(jiān)聽獲取更多數(shù)據(jù)效果,當(dāng)想獲取dom時(shí)發(fā)現(xiàn)怎么也獲取不到,下面這篇文章主要給大家介紹了關(guān)于React報(bào)錯(cuò)解決之ref返回undefined或null的相關(guān)資料,需要的朋友可以參考下2022-08-08
在 React 項(xiàng)目中使用 Auth0 并集成到后端服務(wù)的配置步驟詳解
這篇文章主要介紹了在 React 項(xiàng)目中使用 Auth0 并集成到后端服務(wù)的配置步驟詳解,通過本文詳細(xì)步驟,您可以將 Auth0 集成到 React 項(xiàng)目并與后端服務(wù)交互,需要的朋友可以參考下2024-07-07
解決antd的Table組件使用rowSelection屬性實(shí)現(xiàn)多選時(shí)遇到的bug
這篇文章主要介紹了解決antd的Table組件使用rowSelection屬性實(shí)現(xiàn)多選時(shí)遇到的bug問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08

