下
在之前简单的案例中,redux中保存的counter是一个本地定义的数据:
- 我们可以直接通过同步的操作来dispatch action,state就会被立即更新。
- 但是真实开发中,redux中保存的很多数据可能来自服务器,我们需要进行异步的请求,再将数据保存到redux中。
之前的逻辑:
图一缺陷.jpg
实际上可以做到:
图二合理.jpg
按照之前的逻辑完成案例:Home组件中请求数据,About组件中展示数据:
store/actionCreators.js
import { ADD_NUMBER, SUB_NUMBER,INCREMENT,DECREMENT,CHANGE_BANNERS,CHANGE_RECOMMEND} from './constants.js';
// export function addAction(num) {
// return {
// type: "ADD_NUMBER",
// num
// }
// }
// export const addAction = (num) => {
// return {
// type: "ADD_NUMBER",
// num
// }
// }
export const addAction = num => ({
type: ADD_NUMBER,
num
});
export const subAction = num => ({
type: SUB_NUMBER,
num
});
export const incAction = () => ({
type: INCREMENT
});
export const decAction = () => ({
type: DECREMENT
});
// 轮播图和推荐的action
export const changeBannersAction = (banners) => ({
type: CHANGE_BANNERS,
banners
});
export const changeRecommendAction = (recommends) => ({
type: CHANGE_RECOMMEND,
recommends
});
store/constants.js
export const ADD_NUMBER = "ADD_NUMBER";
export const SUB_NUMBER = "SUB_NUMBER";
export const INCREMENT = "INCREMENT";
export const DECREMENT = "DECREMENT";
export const FETCH_HOME_MULTIDATA = "FETCH_HOME_MULTIDATA";
export const CHANGE_BANNERS = "CHANGE_BANNERS";
store/reducer.js
import { ADD_NUMBER,SUB_NUMBER,INCREMENT,DECREMENT,CHANGE_BANNERS,CHANGE_RECOMMEND } from "./constants.js";
const defaultState = {
counter: 0,
banners: [],
recommends: [],
};
function reducer(state = defaultState, action) {
switch (action.type) {
case ADD_NUMBER:
return { ...state, counter: state.counter + action.num };
case SUB_NUMBER:
return { ...state, counter: state.counter - action.num };
case INCREMENT:
return { ...state, counter: state.counter + 1 };
case DECREMENT:
return { ...state, counter: state.counter - 1 };
case CHANGE_BANNERS:
return { ...state, banners: action.banners };
case CHANGE_RECOMMEND:
return { ...state, recommends: action.recommends };
default:
return state;
}
}
export default reducer;
pages/home.js获取数据 (只做演示,真正项目一般也不放在这里)
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import axios from 'axios';
import { incAction, addAction, changeBannersAction,changeRecommendAction } from '../store/actionCreators'
class Home extends PureComponent {
componentDidMount() {
axios({
url: "http://123.207.32.32:8000/home/multidata",
}).then(res => {
const data = res.data.data;
this.props.changeBanners(data.banner.list);
this.props.changeRecommends(data.recommend.list);
})
}
render() {
return (
<div>
<h1>Home</h1>
<h2>当前计数: {this.props.counter}</h2>
<button onClick={e => this.props.increment()}>+1</button>
<button onClick={e => this.props.addNumber(5)}>+5</button>
</div>
)
}
}
const mapStateToProps = state => ({
counter: state.counter
})
const mapDispatchToProps = dispatch => ({
increment() {
dispatch(incAction());
},
addNumber(num) {
dispatch(addAction(num));
},
changeBanners(banners) {
dispatch(changeBannersAction(banners));
},
changeRecommends(recommends) {
dispatch(changeRecommendAction(recommends));
}
})
export default connect(mapStateToProps, mapDispatchToProps)(Home);
pages/about.js展示数据
import React from 'react';
import { connect } from 'react-redux';
import {decAction, subAction } from "../store/actionCreators";
function About(props) {
console.log("About页面重新渲染了");
return (
<div>
<hr />
<h1>About</h1>
{/* <h2>当前计数: {props.counter}</h2> */}
<button onClick={e => props.decrement()}>-1</button>
<button onClick={e => props.subNumber(5)}>-5</button>
<h1>Banner</h1>
<ul>
{
props.banners.map((item, index) => {
return <li key={item.acm}>{item.title}</li>
})
}
</ul>
<h1>Recommend</h1>
<ul>
{
props.recommends.map((item, index) => {
return <li key={item.acm}>{item.title}</li>
})
}
</ul>
</div>
)
}
const mapStateToProps = state => {
return {
banners: state.banners,
recommends: state.recommends
}
};
const mapDispatchToProps = dispatch => {
return {
decrement: function () {
dispatch(decAction());
},
subNumber: function (num) {
dispatch(subAction(num))
}
}
};
export default connect(mapStateToProps, mapDispatchToProps)(About);
在redux中如何可以进行异步的操作?
中间件(Middleware):
- 目的是在dispatch的action和最终达到的reducer之间,扩展一些自己的代码。
- 比如日志记录、调用异步接口、添加代码调试功能等等
- 第三方库:redux-thunk;
redux-thunk是如何做到让我们可以发送异步的请求? - 默认情况下的dispatch(action),action需要是一个JavaScript的对象
- redux-thunk可以让dispatch(action函数),action可以是一个函数
- 该函数会被调用,并且会传给这个函数一个dispatch函数和getState函数:
dispatch函数用于我们之后再次派发action;
getState函数考虑到我们之后的一些操作需要依赖原来的状态,用于让我们可以获取之前的一些状态;
yarn add redux-thunk
yarn add axios
上述案例的缺陷在“图一缺陷.jpg”中体现出来,接下来按照优化后的:
store/index.js
import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
import reducer from './reducer.js';
//应用一些中间件
const storeEnhancer = applyMiddleware(thunkMiddleware);
const store = createStore(reducer,storeEnhancer);
export default store;
pages/home.js获取数据 (真正项目会这么做)
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import axios from 'axios';
import { incAction, addAction, getHomeMultidataAction } from '../store/actionCreators'
class Home extends PureComponent {
componentDidMount() {
this.props.getHomeMultidata();
}
render() {
return (
<div>
<h1>Home</h1>
<h2>当前计数: {this.props.counter}</h2>
<button onClick={e => this.props.increment()}>+1</button>
<button onClick={e => this.props.addNumber(5)}>+5</button>
</div>
)
}
}
const mapStateToProps = state => ({
counter: state.counter
})
const mapDispatchToProps = dispatch => ({
increment() {
// 本质上传递的是对象
dispatch(incAction());
},
addNumber(num) {
// 本质上传递的是对象
dispatch(addAction(num));
},
getHomeMultidata() {
// 这次传递的是函数
dispatch(getHomeMultidataAction);
}
})
export default connect(mapStateToProps, mapDispatchToProps)(Home);
store/actionCreators.js
import axios from 'axios';
import { ADD_NUMBER, SUB_NUMBER,INCREMENT,DECREMENT,CHANGE_BANNERS,CHANGE_RECOMMEND } from './constants.js';
// export function addAction(num) {
// return {
// type: "ADD_NUMBER",
// num
// }
// }
// export const addAction = (num) => {
// return {
// type: "ADD_NUMBER",
// num
// }
// }
export const addAction = num => ({
type: ADD_NUMBER,
num
});
export const subAction = num => ({
type: SUB_NUMBER,
num
});
export const incAction = () => ({
type: INCREMENT
});
export const decAction = () => ({
type: DECREMENT
});
// 轮播图和推荐的action
export const changeBannersAction = (banners) => ({
type: CHANGE_BANNERS,
banners
});
export const changeRecommendAction = (recommends) => ({
type: CHANGE_RECOMMEND,
recommends
});
// redux-thunk中定义的action函数
export const getHomeMultidataAction = (dispatch, getState) => {
axios({
url: "http://123.207.32.32:8000/home/multidata",
}).then(res => {
const data = res.data.data;
dispatch(changeBannersAction(data.banner.list));
dispatch(changeRecommendAction(data.recommend.list));
})
}
优化完成!
网友评论