Redux中进行异步操作(网络请求)的示例方案
蓝桉cyq 人气:0Redux中的异步操作
在之前简单的案例中,redux中保存的counter是一个本地定义的数据
我们可以直接通过同步的操作来dispatch action,state就会被立即更新。
但是真实开发中,redux中保存的很多数据可能来自服务器,我们需要进行异步的请求,再将数据保存到redux中。
在之前学习网络请求的时候我们讲过,发生网络请求我们有两种方案, 可以直接在组件的钩子函数中发送网络请求, 再将数据存放到store中; 也可以直接在store中发生网络请求
组件中进行异步操作
网络请求可以在class组件的生命周期函数componentDidMount中发送,所以我们可以有这样的结构:
我现在完成如下案例操作:
创建一个组件Category, 在该组件中发送网络请求, 获取banners和recommends的数据;
在About组件中展示banners和recommends的数据;
首先需要创建要派发的action, 以及对应的reducer
// store/actionCreators.jsx import { CHANGE_BANNERS, CHANGE_RECOMMENDS } from "./constants" export const changeBannersAction = (banners) => ({ type: CHANGE_BANNERS, banners }) export const changeRecommendsAction = (recommends) => ({ type: CHANGE_RECOMMENDS, recommends })
// store/reducer.jsx import { CHANGE_BANNERS, CHANGE_RECOMMENDS } from "./constants" const initialState = { banners: [], recommends: [] } export default function reducer(state = initialState, action) { switch(action.type) { case CHANGE_BANNERS: return {...state, [banners: action.banners} case CHANGE_RECOMMENDS: return {...state, recommends: action.recommends} default: return state } }
在Categroy组件中发送网络请求, 并将store中的banners和recommends修改为网络请求后的数据
import React, { PureComponent } from 'react' import axios from 'axios' import { connect } from 'react-redux' import { changeBannersAction, changeRecommendsAction } from '../store/actionCreators' export class Category extends PureComponent { componentDidMount() { // 发送网络请求, 获取到banners和recommends数据 axios.get("http://123.207.32.32:8000/home/multidata").then(res => { const banners = res.data.data.banner.list const recommends = res.data.data.recommend.list console.log(banners, recommends) // 调用映射过来的方法, 修改banners和recommends this.props.changeBanners(banners) this.props.changeRecommends(recommends) }) } render() { return ( <div>Category</div> ) } } // 映射方法用于修改store中的banners和recommends const mapDispatchToProps = (dispatch) => ({ changeBanners(banners) { dispatch(changeBannersAction(banners)) }, changeRecommends(recommends) { dispatch(changeRecommendsAction(recommends)) } }) export default connect(null, mapDispatchToProps)(Category)
目前, store中存放的就是网络请求获取到的数据, 接下来就在About页面进行展示
import React, { PureComponent } from 'react' import { connect } from 'react-redux' export class About extends PureComponent { render() { // 在props中获取到映射过来的数据 const { banners, recommends } = this.props return ( <div> <h2>轮播图展示</h2> <ul> { banners.map(item => { return <li key={item.acm}>{item.title}</li> }) } </ul> <h2>推荐数据展示</h2> <ul> { recommends.map(item => { return <li key={item.acm}>{item.title}</li> }) } </ul> </div> ) } } const mapStateToProps = (state) => ({ banners: state.banners, recommends: state.recommends }) // 表示将数据映射到About组件中 export default connect(mapStateToProps)(About)
redux中进行异步操作
上面的代码有一个缺陷:
我们必须将网络请求的异步代码放到组件的生命周期中来完成;
事实上,网络请求到的数据也属于我们状态管理的一部分,更好的一种方式应该是将其也交给redux来管理;
但是在redux中如何可以进行异步的操作呢?
答案就是使用中间件(Middleware), 如果学习过Express或Koa框架的小伙伴对中间件的概念一定不陌生;
由于在正常情况下,
store.dispatch()
只能派发一个对象, 不能派发函数; 如果dispatch想要派发函数, 我们必须要使用中间件对该store进行增强
使用中间件, 在redux中发送网络请求
首先安装redux-thunk库, 引入中间件
安装redux-thunk库:
npm i redux-thunk
, 在该库中有一个中间件thunk, 如下方式应用thunk中间件
import { createStore, applyMiddleware } from "redux"; import reducer from "./reducer"; // 导入中间件 import thunk from "redux-thunk"; // 应用中间件 const store = createStore(reducer, applyMiddleware(thunk)) export default store
应用之后,
store.dispatch()
就可以派发函数了
// 定义一个返回函数的action export const fetchHomeMultidataAction = () => { function foo() { console.log("aaa") } return foo }
// 派发action const mapDispatchToProps = (dispatch) => ({ fetchHomeMultidata() { // 派发一个函数, 内部返回的函数自动执行 dispatch(fetchHomeMultidataAction()) } })
自动执行action中的返回的函数时, 会传给这个函数一个dispatch函数和getState函数;
dispatch函数
: 用于我们之后再次派发action;
getState函数
: 考虑到我们之后的一些操作需要依赖原来的状态,调用getState函数可以让我们可以获取之前的一些状态;我们就可以在返回的该函数中, 编写异步的网络请求相关代码
import axios from "axios" export const changeBannersAction = (banners) => ({ type: CHANGE_BANNERS, banners }) export const changeRecommendsAction = (recommends) => ({ type: CHANGE_RECOMMENDS, recommends }) export const fetchHomeMultidataAction = () => { // 派发时返回的该函数自动执行, 且传入两个参数dispatch, getState return (dispatch, getState) => { axios.get("http://123.207.32.32:8000/home/multidata").then(res => { const banners = res.data.data.banner.list const recommends = res.data.data.recommend.list // 获取到数据后在派发action dispatch(changeBannersAction(banners)) dispatch(changeRecommendsAction(recommends)) }) } }
加载全部内容