其实React与Redux并没有什么直接的联系。Redux作为一个通用模块,主要还是用来处理应用中state的变更,而展示层不一定是React。
但当我们希望在React+Redux的项目中将两者结合的更好,可以通过react-redux做连接。
当一个react项目组件层级越来越深,页面越来越多的时候,数据在各个组件层级和页面之间传递的需求就会比较多,很多变量也需要做成可全局管理的。在这个时候,redux和react-redux的使用就很有必要了。它们能帮助我们很方便的进行项目全局性的数据管理。
一、redux和React-redux的几个重要概念
1. state
整个应用的状态
1. action
Action 是把数据从应用传到 store 的有效载荷。它是 store 数据的唯一来源。一般来说你会通过 store.dispatch() 将 action 传到 store。
2. reducer
Reducers 指定了应用状态的变化如何响应 actions并发送到 store 的,记住 actions 只是描述了有事情发生了这一事实,并没有描述应用如何更新 state。
3. store
store就是把action和reducer联系到一起的对象,一个redux应用只能有一个store。任何组件都可以直接从store访问特定对象的状态。
在 Redux 中,state数据保存在一个store容器中 ,当一个store接收到一个action,它将把这个action代理给相关的reducer。reducer是一个纯函数,它可以查看之前的状态,执行一个action并且返回一个新的状态。
react-redux
react-redux 若用 redux,一个组件如果想从store存取公用状态,需要进行四步操作:
(1)import 引入 store
(2)getState 获取状态
(3) dispatch 修改状态
(4)subscribe 订阅更新
代码相对冗余,我们想要合并一些重复的操作,而 react-redux 就提供了一种合并操作的方案,react-redux是一个轻量级的封装库,核心方法只有两个:
- Provider Provider 将 store 放进 this.context 里,省去了 import 这一步
- connect connect将 getState、dispatch 合并进了this.props,并自动订阅更新,简化了另外三步。
Provider
[Context]()
来实现的。import React from 'react'
import PropTypes from 'prop-types'
export class Provider extends React.Component {
// 需要声明静态属性childContextTypes来指定context对象的属性,是context的固定写法
static childContextTypes = {
store: PropTypes.object
}
// 实现getChildContext方法,返回context对象,也是固定写法
getChildContext() {
return { store: this.store }
}
constructor(props, context) {
super(props, context)
this.store = props.store
}
// 渲染被Provider包裹的组件
render() {
return this.props.children
}
}
connect
connect 的作用是连接React组件与 Redux store,它包在我们的容器组件的外一层,它接收上面 Provider 提供的 store 里面的 state 和 dispatch,传给一个构造函数,返回一个对象,以属性形式传给我们的容器组件。
它共有四个参数mapStateToProps, mapDispatchToProps, mergeProps以及options。
mapStateToProps 的作用是将store里的state(数据源)绑定到指定组件的props中 mapDispatchToProps 的作用是将store里的action(操作数据的方法)绑定到指定组件的props中 另外两个方法一般情况下使用不到
connect的调用方式:connect(mapStateToProps, mapDispatchToProps)(App)
。
export function connect(mapStateToProps, mapDispatchToProps) {
return function (Component) {
class Connect extends React.Component {
componentDidMount() {
//从context获取store并订阅更新
this.context.store.subscribe(this.handleStoreChange.bind(this));
}
handleStoreChange() {
// 触发更新
// 触发的方法有多种,这里为了简洁起见,直接forceUpdate强制更新,读者也可以通过setState来触发子组件更新
this.forceUpdate()
}
render() {
return (
<Component
// 传入该组件的props,需要由connect这个高阶组件原样传回原组件
{...this.props}
// 根据mapStateToProps把state挂到this.props上
{...mapStateToProps(this.context.store.getState())}
// 根据mapDispatchToProps把dispatch(action)挂到this.props上
{...mapDispatchToProps(this.context.store.dispatch)}
/>
)
}
}
//接收context的固定写法
Connect.contextTypes = {
store: PropTypes.object
}
return Connect
}
}