在用react开发项目时,难免会遇到一些复杂的情况。例如状态管理这一块,组件多的时候组件之间相互联系很麻烦,通常利用redux来进行统一状态管理。而redux默认的是同步方法,并且当异步请求后台接口时,我们需要根据结果执行对应的操作,这时我们可以利用中间件redux-thunk来实现。下面是我学习后的总结。
简单复习一下。说白了,store就是存储state的仓库,action通过dispatch与store取得联系,告诉reducers要进行什么操作,然后对应的reducer实际操作state,store将结果反馈给组件。
合理搭建项目结构方便维护、开发。这是我比较喜欢的一款:
src下的components是用来放公用组件的,如header、footer、消息框。
containers中是每个页面的大容器,而每个页面又有各自的组件,最终聚合在index里面。其中,App又把所有容器聚合,放到src目录下的入口文件index.js里
redux里又分为actions、middleware、reducers文件夹,以及唯一的store。
这样就是一个基本结构了
下面是我仿大众点评App时遇到的场景:下拉时显示更多商品。
这里需要执行一个异步操作向后台请求数据,得到结果后更新组件视图。那么这时就需要用到redux-thunk这个中间件了。
中间件可以理解为一个函数,对store.dispatch进行了改造,在发出 Action 后按顺序依次执行中间件实现其他功能,最后执行 Reducer 操作state。大部分功能都有现成的,例如这里的redux-thunk。
为什么要用redux-thunk呢?因为dispatch本身接收的是一个对象,例如向后台请求数据时,我们不知道请求是否在进行中,不知道结果是成功还是失败,应该执行哪个action,并且redux默认是同步方法。我们想要的情况是 当接受到结果时再继续往下执行。redux-thunk的作用就是使dispatch接收一个函数,这样我们就可以执行异步操作,向后台请求数据,根据结果执行对应action,所以这里需要细化actions。
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import rootReducer from "./reducers";
// applyMiddleware(...middlewares)会让中间件连成一个数组,按顺序依次执行
const middlewares = [thunk]
const store = createStore(rootReducer, applyMiddleware(...middlewares));
export default store;
import http from '../../utils/http'
//获取猜你喜欢列表请求
export const GET_LIKES_SUCCESS = "GET_LIKES_SUCCESS"
export const GET_LIKES_FAIL = "GET_LIKES_FAIL"
export const HomeActions = {
//加载猜你喜欢列表数据
getLikes: () => (dispatch,getState) => {
const { pageSize,perPage } = getState().home.likes;
// 封装好ajax的http请求
http.get("/getLikes",{perPage,pageSize}).then((res) => {
return dispatch({
response: res.data,
type: GET_LIKES_SUCCESS
})
}).catch((err)=> {
return dispatch({
type: GET_LIKES_FAIL
})
})
},
other: () => {
...
}
}
这个场景就是当子组件下拉到底时,触发父组件的loadMore方法,该方法会先请求数据,等后台返回结果后再执行action
import React, { Component } from 'react';
import List from './components/List'
import { bindActionCreators } from "redux";
import { connect } from "react-redux";
// 加载actions
import { HomeActions } from "../../redux/actions/home";
class Home extends Component {
loadMore = () => {
// 注意这里HomeActions是节点流中的
this.props.HomeActions.getLikes()
}
render() {
const {likes} = this.props
return (
<div className="container">
<List data = {likes} getLikes={this.loadMore}/>
</div>
);
}
}
// 这两个方法遍历state和action分发给组件
const mapStateToProps = (state, props) => {
return {
likes: state.home.likes,
}
}
const mapDispatchToProps = dispatch => {
return {
HomeActions: bindActionCreators(HomeActions, dispatch)
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Home)
import { combineReducers} from "redux"
//初始数据
const initialState = {
likes: {
perPage: 0,
pageSize: 5,
goods: [],
fail: false
},
discounts: {
fail: false,
goods: []
}
};
//猜你喜欢reducer
const likes = (state = initialState.likes, action) => {
switch (action.type) {
case "GET_LIKES_SUCCESS":
return {
type: "GET_LIKES_SUCCESS",
...state,
pageCount: state.pageSize*(state.perPage+1),
goods: state.goods.concat(action.response.data.goods)
}
case "GET_LIKES_FAIL":
return {
type: "GET_LIKES_FAIL",
...state,
fail: true
}
default:
return state
}
}
//其他reducer
const other = (state = initialState.discounts, action) => {
...
};
const reducer = combineReducers({
other,
likes
})
export default reducer
以上就是一个完整的流程。下面是我的实际应用。
打印一下后端返回的数据,根据结果 执行成功后的action。
在Home组件里的List子组件注入data,也就是这个组件需要用到的那部分state。打印一下新的state:
render() {
const {data} = this.props
console.log(data)
...
以上就是我对redux项目的异步请求中间件的理解和简单应用。实际项目场景会更复杂,例如 判断是否正在请求、针对各种返回结果的处理。