1、为什么要学习redux?
随着Javascript的应用开发日趋复杂,javascript需要管理比任何时候都要多的state(状态)。
- javascript需要管理的状态越来越多,越来越复杂;
- 这些状态包括服务器返回的数据、缓存数据、用户操作产生的数据等等,也包括一些UI的状态,比如某些元素是否被选中,是否显示加载动态,当前分页的数据。
管理不断变化的state状态是非常困难的:
- 状态之间相互存在依赖,一个状态的变化会引起另一个状态的变化,view页面也有可能会引起状态的变化。
2、redux是什么?
:::info Redux是一个流行的JavaScript框架,为应用程序提供一个可预测的状态容器。Redux基于简化版本的Flux框架,Flux是Facebook开发的一个框架。在标准的MVC框架中,数据可以在UI组件和存储之间双向流动,而Redux严格限制了数据只能在一个方向上流动。redux的工作原理汝下图所示: :::
在Redux中,所有的数据(比如state)被保存在一个被称为store的容器中 → 在一个应用程序中只能有一个。store本质上是一个状态树,保存了在应用中需要保存的状态。任何UI组件都可以直接从store访问特定对象的状态。要通过本地或远程组件更改状态,需要分发一个action。分发在这里意味着将可执行信息发送到store。当一个store接收到一个action,它将把这个action代理给相关的reducer。reducer是一个纯函数,它可以查看之前的状态,执行一个action并且返回一个新的状态。
3、使用redux完成计数器的案例
计数器对应的状态就是当前的数字,行为就是增加或者减少,我们使用redux来管理这个计数器案例。
// redux的具体使用 计数器案例
// 1、引入redux 在这里需要使用require()函数来引入 在脚手架中可直接使用commonjs的语法
const redux = require('redux')
// 2、定义redux需要管理的状态
const defaultStatus = {
counter: 200
}
// 3、定义需要修改状态的行为action
const action1 = { type: 'INCREMENT' }
const action2 = { type: 'DECREMENT' }
// 4、创建reducer 形成为(state,action)=> state的纯函数
function reducer(state = defaultStatus, action) {
switch (action.type) {
case 'INCREMENT':
return {...state, counter: state.counter + 1 }
case 'DECREMENT':
return {...state, counter: state.counter - 1 }
default:
return state
}
}
// 5、创建redux的store来存放应用的状态api是 { subscribe, dispatch, getState }
let store = redux.createStore(reducer)
// 6、可以手动订阅更新 也可以事件绑定到视图层 事件订阅后 就会回调事件订阅的函数 回调函数就会自动执行
store.subscribe(() => {
const newState = store.getState().counter
console.log('订阅获取最新的状态', newState)
})
// 7、改变内部state唯一方法是 dispatch一个action action可以被序列化 用于记录和储存下来 后期还可以以回放的形式执行
store.dispatch(action1)
store.dispatch(action2)
总结:使用redux管理状态的几个步骤 1、引入redux,引入的方式是不相同的 2、创建我们需要管理的初始化状态(一般为一个对象) 3、创建我们修改数据的行为action(一般为一个对象,里面定义修改数据的方法类型,修改的数据) 4、创建reducer纯函数,将我们的状态与行为联系在一起,根据不同的行为,内部处理以后,返回新的状态(注意:不能修改原始的状态) 5、使用redux来创建全局的状态管理仓库store,将我们的纯函数reducer作为参数传入进去 6、订阅store仓库中state发生变化的事件,订阅后将获取store中最新的状态 7、使用store来派发修改状态的行为。
4、拆分redux、模块化开发
在项目中对redux进行相应的拆分,分为不同的模块,使不同的模块完成不同的功能。
4.1 actionCreators.js文件
作用:定义生成action对象的函数。
// 定义修改数据的行为
// 引入常量
import {
INCREMENT,
DECREMENT,
MUL
} from './constants.js'
// 数据增加 普通函数定义 不推荐
function incrementAction(num) {
return {
type: INCREMENT,
num
}
}
// 数据减少 箭头函数定义 不推荐
const decrementAction = (num) => {
return {
type: DECREMENT,
num
}
}
// 数据相乘 箭头函数定义 简写形式 推荐写法
const mulAction = num => ({
type: MUL,
num
})
// 将定义的函数进行导出
export { incrementAction, decrementAction, mulAction }
4.2 constants.js
作用:定义action的类型,进行导出,在实际的业务组件和reducer纯函数中使用。
export const INCREMENT = 'INCREMENT'
export const DECREMENT = 'DECREMENT'
export const MUL = 'MUL'
4.3 reducer.js纯函数
作用:将我们需要管理的状态和需要派发的行为进行结合,根据派发行为的不同,返回不同的数据状态。
// 1、需要定义redux管理的初始化状态
// 2、引入修改状态的行为action
// 引入action
import {
INCREMENT,
DECREMENT,
MUL
} from './constants.js'
// 定义初始化状态
const defaultStatus = {
counter: 100
}
// 定义纯函数reducer
function reducer(state = defaultStatus, action) {
switch(action.type) {
case INCREMENT:
return {...state, counter: state.counter + action.num }
case DECREMENT:
return {...state, counter: state.counter - action.num }
case MUL:
return {...state, counter: state.counter * action.num }
default:
return state
}
}
// 将reducer函数默认导出
export default reducer;
4.3 index.js文件-store数据仓库的入口文件
原理:引入redux,创建store数据仓库,管理传入的状态,将reducer纯函数作为参数传入,再将store进行导出,提供给我们实际的业务组件使用。
// 在这里应该将store进行导出 提供给业务组件使用 在业务组件中只需要使用store进行dispatch派发action即可
// 需要引入redux
import redux from 'redux'
// 引入纯函数reducer纯函数作为参数
import reducer from './reducer.js'
const store = redux.createStore(reducer)
export default store;
4.4 业务组件使用store的步骤
方法:引入store, 引入actionCreators文件,订阅store事件,并且派发相应的行为。
// 当作业务组件使用 直接使用store 调用store来派发行为
// 引入store
import store from "./store/index.js"
// 导入入action
import {
incrementAction,
decrementAction,
mulAction
} from "./store/actionCreators.js"
// 订阅store状态发生变化的事件
store.subscribe(() => {
// 获取最新的状态值
const newState = store.getState();
console.log(newState);
})
// 派发修改状态的行为
store.dispatch(incrementAction(200));
store.dispatch(decrementAction(200));
store.dispatch(mulAction(5));
4.5 在react组件中使用的步骤
步骤: 1、在react组件的生命周期中,componentDidMount中使用store进行数据的订阅。订阅完成后,一旦我们的数据发生了变化,我们的订阅事件就会发生回调,此时数据更新后,我们调用this.setState()函数,就会重新调用render方法,界面就会更新。 2、在dom元素挂载以后,监听页面的相关的事件或者在其它的时机使用store来派发行为。再次更新页面数据。
4.6 redux使用的流程图
需要注意的事项:
1、redux推荐我们全局只创建一个store对象,不需要创建多个。
4.7 在node中,由于低版本的node不支持ES6的导入(import)和导出(export)的功能,在node的13.X版本下,我们需要进行一些特殊的配置,让node支持我们平时习惯使用的ES Module的功能,对package.json文件进行具体的配置,见下图:
截图:
5、redu在组件中的使用
5.1 计数器案例
原理:数据的原始状态保存在redux中,创建store状态仓库,向外暴露store,那么我们的组件就可以根据store来获取最新的状态。同时,在组件挂载完毕以后,组件可以订阅subscribe全局仓库store书记的变化,一旦数据发生变化,我们使用setState来修改状态,组件就会重新进行渲染。我们就可以获取到最新的状态。同时在组件中我们可以进行dom元素的监听,可以利用stote来派发相应事件,修改redux中的状态。
About组件
import React, { PureComponent } from 'react'
// 引入全局状态store
import store from '../store'
import { addAction, subAction } from '../store/actionCreators'
export default class About extends PureComponent {
constructor(props) {
super(props)
this.state = {
// 组件的状态为 store全局仓库的状态
counter: store.getState().counter
}
}
componentDidMount() {
this.unsubscribe = store.subscribe(() => {
const newState = store.getState().counter
this.setState({
counter: newState
})
})
}
componentWillUnmount() {
this.unsubscribe()
}
render() {
return (
<div>
<h2>About组件</h2>
<h2>{ this.state.counter }</h2>
<button onClick={ () => this.btn1Click()}>增加增加</button>
<button onClick={ () => this.btn2Click()}>降低降低</button>
</div>
)
}
btn1Click() {
store.dispatch(addAction())
}
btn2Click() {
store.dispatch(subAction())
}
}
组件Home
import React, { PureComponent } from 'react'
// 引用全局状态
import store from '../store'
import { addAction, subAction } from '../store/actionCreators'
export default class Home extends PureComponent {
constructor(props) {
super(props)
this.state = {
// 将全局的状态分发到组件中 在组件中可直接进行展示
counter: store.getState().counter
}
}
componentDidMount() {
// 订阅事件 调用渲染函数 更新页面的数据
this.unsubscribe = store.subscribe(() => {
const newState = store.getState().counter
// 修改页面 获取最新的状态数据
this.setState({
counter: newState
})
})
}
componentWillUnmount() {
// 组件卸载的时候 取消订阅事件
this.unsubscribe()
}
render() {
return (
<div>
<h2>Home组件</h2>
<h2>{ this.state.counter }</h2>
<button onClick={ () => this.btn1Click() }>数据增加</button>
<button onClick={ () => this.btn2Click() }>数据降低</button>
</div>
)
}
btn1Click() {
// 派发事件
store.dispatch(addAction())
}
btn2Click() {
store.dispatch(subAction())
}
}
5.2 计数器案例-自己封装的connect高阶函数
原理:在我们实际的业务组件中,组件A和组件B都有相同的逻辑,这个逻辑是,实际的业务组件先引入我们的状态仓库store,因为在这个仓库中我们可以获取我们最新的状态,我们可以监听、订阅我们状态发生变化的时机,订阅后数据发生变化的时候,我们可以更新页面数据,那么我们页面的数据就是最新的数据。在组件将要卸载的时候,我们可以取消订阅的事件。在DOM的事件中,我们事件的监听都有自己的回调函数,那么在监听后我们可以dispatch来派发action, 派发action, 就意味这可以修改相应的数据。一旦我们的数据发生了变化,订阅事件就会重新被激活,页面就会重新进行渲染,这就是内部的逻辑。 存在的问题:在上述的逻辑中,我们可以看出,我们实际的每个业务组件都需要相同的操作逻辑,获取store中的状态,将store中的状态保存为组件自身的状态,然后监听、订阅store发生的变化,然后修改组件自身的状态,更新页面,在组件卸载的时候,取消订阅,在操作DOM的时候,使用store来派发事件,修改store中的状态,页面重新进行渲染。所有的组件,都是这一套的逻辑,缺点是代码的重复率太高了,相同的代码有多个地方。而且整个流程操作比较复杂。 解决方案:抽象出一个高阶组件(实际上是一个函数),将我们业务组件需要做的事情,全部抽取到高阶组件中,业务组件实际需要完成的事情,都在高阶组件中完成,高阶组件将新的状态和修改状态的方法全部通过props传递到实际的业务组件中,我们的业务组件就可以直接使用。实际上,我们的第三方插件就是react-redux就是用来干这件事情的。
import { PureComponent } from "react";
import store from '../store'
function connect(mapStateToProps, mapDispatchToProps) {
return function enhanceHOC(WrappedComponent) {
return class extends PureComponent {
constructor(props) {
super(props)
this.staste = {
storeState: mapStateToProps(store.getState())
}
}
componentDidMount() {
// 订阅store发生的变化并更新数据
this.unsubscribe = store.subscribe(() => {
this.setState({
storeState: mapStateToProps(store.getState())
})
})
}
componentWillUnmount() {
this.unsubscribe()
}
store
render() {
return <WrappedComponent {...this.props}
{...mapStateToProps(store.getState())}
{...mapDispatchToProps(store.dispatch)} />
}
}
}
}
// 将connect函数进行导出
export default connect;
在组件中使用,将公用的代码抽取出去了
About组件:
import React, { PureComponent } from 'react'
import connect from '../utils/connect'
import {incrementAction, addNumberAction} from '../store/actionCreators'
class About extends PureComponent {
render() {
return (
<div>
<h2>about组件</h2>
<h2>当前技术:{this.props.counter}</h2>
<button onClick={() => this.props.btn1Click() }>+1</button>
<button onClick={() => this.props.btn2Click(5) }>+5</button>
</div>
)
}
}
const mapStateToProps = state => {
return {
counter: state.counter
}
}
const mapDispatchToProps = dispatch => {
return {
btn1Click() {
dispatch(incrementAction())
},
btn2Click(num) {
dispatch(addNumberAction(num))
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(About)
Home组件:
import React, { PureComponent } from 'react'
// 引入connect函数
import connect from '../utils/connect'
import {decrementAction, subNumberAction} from '../store/actionCreators'
class About extends PureComponent {
render() {
return (
<div>
<h2>Home组件</h2>
<h2>当前技术:{this.props.counter}</h2>
<button onClick={() => this.props.increment() }>-1</button>
<button onClick={() => this.props.addNumber(5) }>-5</button>
</div>
)
}
}
const mapStateToProps = state => {
return {
counter: state.counter
}
}
const mapDispatchToProps = dispatch => {
return {
increment() {
dispatch(decrementAction())
},
addNumber(num) {
dispatch(subNumberAction(num))
}
}
}
// 函数柯里化
export default connect(mapStateToProps, mapDispatchToProps)(About)
5.3 计数器案例-抽取store(创建StoreContext)
上述代码的缺点:在我们自己封装的高阶函数中,还是存在对store的依赖,当把它看成是一个工具函数的时候,我们就不应该直接使用实际的业务数据,我们需要在使用的时候,应该从他的上一级组件进行传入,而不是直接对业务数据进行直接的引入。所以我们引入context函数。 context作用:创建一个context上下文对象,对使用store的组件进行包裹,然后通过组件标签的props属性来传递store,在实际的业务组件中就可以使用this.context来直接获取store的值,然后对这个store的值进行订阅,转发到实际的业务组件中去。这就是原理。
import React from 'react';
// 创建context上下文对象
const StoreContext = React.createContext()
export default StoreContext
5.4 计数器案例-修改context函数的用法
import { PureComponent } from "react";
// 这里就不需要了
// import store from '../store'
// 引入context
import StoreContext from './context'
# 在这个高阶函数中 就不需要使用store 而是通过context来接收值 我们会在组件的外面的包裹一层context的高阶函数 context作为生产者 为我们提供状态数据 那么我们的业务组件也就是我们的消费者直接通过this。context来获取最新的状态即可。
function connect(mapStateToProps, mapDispatchToProps) {
return function enhanceHOC(WrappedComponent) {
class EnhanceComponent extends PureComponent {
constructor(props, context) {
super(props, context)
this.staste = {
storeState: mapStateToProps(context.getState())
}
}
componentDidMount() {
// 订阅store发生的变化并更新数据
this.unsubscribe = this.context.subscribe(() => {
this.setState({
storeState: mapStateToProps(this.context.getState())
})
})
}
componentWillUnmount() {
this.unsubscribe()
}
render() {
return <WrappedComponent {...this.props}
{...mapStateToProps(this.context.getState())}
{...mapDispatchToProps(this.context.dispatch)} />
}
}
# 接收context传递的参数
EnhanceComponent.contextType = StoreContext
// 将组件返回
return EnhanceComponent
}
}
// 将connect函数进行导出
export default connect;
5.5 在组件中使用context
import React, { PureComponent } from 'react'
import About from './16_react-redux/pages/About'
import Home from './16_react-redux/pages/Home'
// 引入StoreContext
import StoreContext from './16_react-redux/utils/context'
// 引入store
import store from './16_react-redux/store'
export default class App extends PureComponent {
render() {
return (
<div>
{/* 为组件提供context */}
<StoreContext.Provider value={store}>
<About />
<hr/>
<Home />
</StoreContext.Provider>
</div>
)
}
}
# 注意 在这里使用的是StoreContext组件 传递的是一个value的值,那么在我们的子组件中,直接就可以使用this.context使用就可以 不需要使用 this.context.store 非常重要
6、使用react-redux来改造计数器案例
原理:redux代替我们封装了connect函数和context函数
# 在父组件中进行使用 数据传递给子组件
import React, { PureComponent } from 'react'
import About from './16_react-redux/pages/About'
import Home from './16_react-redux/pages/Home'
// 引入StoreContext
// import StoreContext from './16_react-redux/utils/context'
// 引入store
// import store from './16_react-redux/store'
# 使用react-redux中的Provider 直接react-redux提供的高阶组件Provider 将组件映射为标签即可,将我们实际的业务组件放置于这个Provider高阶组件中即可
import { Provider } from 'react-redux'
import store from './16_react-redux/store'
export default class App extends PureComponent {
render() {
return (
<div>
{/* 为组件提供context */}
# 需要注意的是 我们在使用context的时候,在高阶组件中传值使用的是value属性,但是在react-redux中,他要求我们必须 使用store来传递数据 非常重要 不用这个属性的话 数据将无法进行传递
<Provider store={store}>
<About />
<hr/>
<Home />
</Provider>
</div>
)
}
}
6.1 在具体的业务组件中进行使用
import React, { PureComponent } from 'react'
// import connect from '../utils/connect'
// 引入react-redux中的connect函数 非常重要
# import { connect } from 'react-redux'
import {incrementAction, addNumberAction} from '../store/actionCreators'
class About extends PureComponent {
render() {
return (
<div>
<h2>about组件</h2>
<h2>当前技术:{this.props.counter}</h2>
<button onClick={() => this.props.btn1Click() }>+1</button>
<button onClick={() => this.props.btn2Click(5) }>+5</button>
</div>
)
}
}
const mapStateToProps = state => {
return {
counter: state.counter
}
}
const mapDispatchToProps = dispatch => {
return {
btn1Click() {
dispatch(incrementAction())
},
btn2Click(num) {
dispatch(addNumberAction(num))
}
}
}
// 使用react-redux中的contect函数
export default connect(mapStateToProps, mapDispatchToProps)(About)
6.2 react-redux在react框架中使用总结
// react-redux的使用原理总结:
1、安装react-redux第三方库
yarn add react-redux
2、在具体的业务组件中直接使用connect函数
import { connect } from 'react-redux'
// 定义变量
const mapStateToProps = {}
const mapStateToDispatch = {}
export default connect(mapStateToProps, mapStateToDispatch)(ComponentName)
3、在跟组件中向下传递store
import store from 'store/index.js';
使用Provider
import { Provider } from 'react-redux';
映射为相应的标签 相当于将store以全局变量的方式都传递给了所有的子组件
<Provider store={store}>
<App />
<Provider>
4、在类组件中可以直接使用this.props的属性来访问全局传入的store对象
在函数式组件中直接使用props来接收跟组件传递过来的参数
7、组件中的异步操作
在之前简单的案例中,redux中保存的counter是一个本地定义的数据:
- 我们可以直接通过同步的操作来dispatch action,state就会被立即更新。
- 但是真实开发中,redux中保存的很多数据可能来自服务器,我们需要进行异步的请求,再将数据保存到redux中。
在之前学习网络请求的时候我们讲过,网络请求可以在class组件的componentDidMount中发送,所以我们可以有这样的结构:
7.1 在react的redux中发送异步的网络请求
import React, { PureComponent } from 'react'
// 引入react-redux中的connect函数
import { connect } from 'react-redux'
import {incrementAction, addNumberAction,changeBannerAction, changeRecommendAction} from '../store/actionCreators'
// 在react中发送响应的网络请求
// 引入axios
import axios from 'axios'
class About extends PureComponent {
componentDidMount() {
axios({url: 'http://123.207.32.32:8000/home/multidata'}).then(res => {
console.log(res.data);
// 轮播图列表
const banner = res.data.data.banner.list
// 推荐列表
const recommend = res.data.data.recommend.list
// 可以通过action派发事件
this.props.changeBanner(banner)
this.props.changeRecommend(recommend)
})
}
render() {
return (
<div>
<h2>about组件</h2>
<h2>当前技术:{this.props.counter}</h2>
<button onClick={() => this.props.btn1Click() }>+1</button>
<button onClick={() => this.props.btn2Click(5) }>+5</button>
</div>
)
}
}
const mapStateToProps = state => {
return {
counter: state.counter
}
}
const mapDispatchToProps = dispatch => {
return {
btn1Click() {
dispatch(incrementAction())
},
btn2Click(num) {
dispatch(addNumberAction(num))
},
changeBanner(banner) {
dispatch(changeBannerAction(banner))
},
changeRecommend(recommend) {
dispatch(changeRecommendAction(recommend))
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(About)
7.2 actionCreateor.js文件
import { INCREMENT, ADD_NUMBER, DECREMENT, SUB_NUMBER, CHANGE_BANNER, CHANGE_RECOMMEND } from './constants'
export const incrementAction = () => ({
type: INCREMENT,
})
export const addNumberAction = num => ({
type: ADD_NUMBER,
num
})
export const decrementAction = () => ({
type: DECREMENT
})
export const subNumberAction = num => ({
type: SUB_NUMBER,
num
})
// 修改banner的action
export const changeBannerAction = banner => {
return {
type: CHANGE_BANNER,
banner
}
}
// 修改推荐数据的action
export const changeRecommendAction = recommend => {
return {
type: CHANGE_RECOMMEND,
recommend
}
}
7.3 constants.js常量文件
const INCREMENT = 'INCREMENT';
const ADD_NUMBER = 'ADD_NUMBER';
const DECREMENT = 'DECREMENT';
const SUB_NUMBER = 'SUB_NUMBER';
// 修改banner和recommend
const CHANGE_BANNER = 'CHANGE_BANNER';
const CHANGE_RECOMMEND = 'CHANGE_RECOMMEND'
export {
INCREMENT,
ADD_NUMBER,
DECREMENT,
SUB_NUMBER,
CHANGE_BANNER,
CHANGE_RECOMMEND
}
7.4 reducer.js处理函数文件
import { INCREMENT, ADD_NUMBER, DECREMENT, SUB_NUMBER, CHANGE_BANNER, CHANGE_RECOMMEND } from './constants'
const defaultState = {
counter: 100,
banner: [],
recommend: []
}
function reducer(state = defaultState, action) {
switch(action.type) {
case INCREMENT:
return {...state, counter: state.counter + 1 }
case ADD_NUMBER:
return {...state, counter: state.counter + action.num }
case DECREMENT:
return {...state, counter: state.counter - 1 }
case SUB_NUMBER:
return {...state, counter: state.counter - action.num }
// 处理banner和recommend
case CHANGE_BANNER:
return {...state, banner: action.banner }
case CHANGE_RECOMMEND:
return {...state, recommend: action.recommend }
default:
return state
}
}
export default reducer;
7.5 在其他的组件中使用react-redux中的数据
import React, { PureComponent } from 'react'
// 引入connect函数
// import connect from '../utils/connect'
import { connect } from 'react-redux'
import {decrementAction, subNumberAction} from '../store/actionCreators'
class About extends PureComponent {
render() {
return (
<div>
<h2>Home组件</h2>
<h2>当前技术:{this.props.counter}</h2>
<button onClick={() => this.props.increment() }>-1</button>
<button onClick={() => this.props.addNumber(5) }>-5</button>
<hr/>
<h2>轮播图</h2>
<ul>
{
this.props.banner.map(item => {
return (
<li key={item.acm}>
<span>{ item.title }</span>
<a href={item.image} style={{ marginLeft: '10px'}}>点击查看图片</a>
</li>
)
})
}
</ul>
<h2>推荐列表</h2>
<ul>
{
this.props.recommend.map(item => <li key={item.acm}>{item.title}</li>)
}
</ul>
</div>
)
}
}
const mapStateToProps = state => {
return {
counter: state.counter,
# 非常重要
banner: state.banner,
recommend: state.recommend
}
}
const mapDispatchToProps = dispatch => {
return {
increment() {
dispatch(decrementAction())
},
addNumber(num) {
dispatch(subNumberAction(num))
}
}
}
// 函数柯里化
export default connect(mapStateToProps, mapDispatchToProps)(About)
7.6 在组件中使用react-redux的步骤总结
在组件中异步请求的数据如何交给我们的redux进行管理? 1、在类组件的生命周期函数componentDidMount() 中发送异步请求,并获取相应的异步数据。 2、将我们需要dispatch派发action的地方定义一个方法,这个方法将在组件中映射为mapStateToDispatch(),我们的组件获取了异步数据后,调用这个方法、派发相应的action。 3、当派发了相应的action后,就会自动调用我们的reducer方法,reducer函数集那个会根据我们action.type的类型对数据进行保存和相应的处理。此时我们的数据就实时的保存进了redux的store中了。 4、在其它的业务组件中如何使用store中的state,我们需要的数据在在mapStateToProps()中声明即可。那么此时我们的store中的状态就会映射为相应状态,只需要在组件中使用我们的props即可。