目标
- 为什么要使用
react-redux? react-redux为开发提供了什么?
回顾redux的基本使用
在使用redux之前,需要了解的是**redux不是react专属的**,所以在vue,angular,甚至jQuery中都可以使用。
使用原生JavaScript来使用redux,在node环境下。
// 安装
npm install redux
开始使用redux
// index.js
// 导入redux,不用多说
const redux = require('redux')
// 第一步: 初始化一个变量
const initState = {
count: 0
}
// 第二步: 创建一个store对象,利用redux提供的createStore,参数为一个reducer函数
const store = redux.createStore(reducer)
// 第三步:由于上面需要一个reducer函数,所以创建一个reducer函数
function reducer(state = initState, action) {
switch(action.type) { //根据类型,判断执行哪个action
case 'ADD': { //加
return {...state, count: state.count + 1}
}
case 'SUB': { //减
return {...state, count: state.count - action.num}
}
default: { //返回默认值
return state
}
}
}
由于处于node环境,上面的第三步 和 第二步需要对调一下位置,理解意思就行了。
上面创建一个store对象就已经存在了,那么就可以开始使用store对象。
// 第四步:调用store对象提供的subscribe方法,来监听store的变化,只要发生变化,就会触发
store.subscribe(() => {
console.log(store.getState());
})
// 第五步:触发动作(使用store对象提供的dispatch来触发reducer函数)
const action = {
type: 'SUB',
num: 12
}
store.dispatch(action)
// 根据type去匹配reducer函数中的type值,从而修改state
上面大致就是redux的基本执行流程:
- 定义一个
初始值。 - 创建一个
store对象。 - 定义一个
reducer函数,在创建store对象的时候使用。 - 调用
store.subscribe来监听state的变化。 - 触发动作(改变state的值),
store.dispatch()执行动作。
react中使用redux
虽然redux可以在其他的地方使用,但是最普遍的还是在react中使用,实现数据的状态管理。
如果在react组件中,使用redux的话,肯定会有三个步骤:
- 导入state数据到组件。
- 在组件加载的时候,监听
state数据的变化。 - 在组件卸载的时候,取消监听state数据变化。
// 那么就会出现,每个组件中,大致有这样的几行代码
// 导入整体的state
import stores from 'src/stores'
// 在组件加载的时候,监听state数据变化
componentDidMount() {
this.unSubScribe = store.subscribe(() => {
this.setState({
counter: stores.getState.count
})
})
}
// 组件卸载的时候,取消监听
componentWillUnmount() {
this.unSubScribe()
}
store.subscribe()的返回值,是一个取消监听的函数,执行该函数,就取消监听。
这样就会想,如果每个组件都有这样的几行代码,那么根据开发思想,就会进行代码抽离。
代码抽离
抽离的实现: 利用高阶组件(HOC)
import React, {PureComponent} from 'react
// 导入store
import stores from '../stores'
export default function connect(mapStateToProps, mapDispatchToProps) {
return function HandleNewCom(WrapComponent) {
return class extends PureComponent { //这里是使用的class表达式,可以不用写类名
constructor(props) {
super(props)
this.state = {
storeState: mapStateToProps(stores.getState())
}
}
//在生命周期中处理订阅和取消订阅
componentDidMount() {
this.unSubScribe = store.subscribe(() => {
this.setState({
storeState: mapStateToProps(stores.getState())
})
})
}
componentWillUnmount() {
this.unSubScribe()
}
//这里我们把传递过来组件,重新return出去,也把store中的state值和store.dispatch传送过去
return<WrapComponent
{...this.props }
{...this.mapStateToProps(store.getState())}
{...this.mapDispatchToProps(store.dispatch) }
/>
}
}
}
简单分析:
-
执行
connect函数,返回一个组件,调用connect函数,就需要你手动的传递两个参数,并且这两个参数也是函数mapStateToProps: 映射state到props中去。mapDispatchToProps: 映射dispatch到props中。
-
connect函数,返回一个函数组件,函数组件接受一个参数,该参数也是组件。- 这一步的目的就是为了
注入state和dispatch到props中 ...this.mapStateToProps(store.getState()): 注入mapStateToProps的返回值到props中...this.mapDispatchToProps(store.dispatch): 注入mapDispatchToProps的返回值到props中
- 这一步的目的就是为了
具体使用:
// 定义两个函数,作为connect的参数
const mapStateToProps = (state) => { // state:store.getState()调用传入的
return {
counter: state.counter
}
};
const mapDispatchToProps = (dispatch) => { // dispatch: store.dispatch 调用传入的
return {
increment: (...args) => dispatch(actions.increment(...args)),
}
};
// 调用connect函数,返回一个函数组件
const Com = connect(mapStateToProps, mapDispatchToProps)
// 函数组件,接受一个参数:组件,返回一个组件(HOC)
const NewCount = Com(Count)
export default NewCount;
// 连起来写
export default connect(mapStateToProps, mapDispatchToProps)(Count)
这样,redux在组件中,就不用每个组件都去写一边redux的监听事件等等,只需要调用connect函数即可,返回一个新的组件,新的组件就具有state的一些列操作。
react-redux的出现
在上面的connect函数实现中,其实还是比较的难理解,有点绕弯,高阶组件的应用什么的。(反正,我是理解很多遍的,太菜了)。
那么对于开发者而言,我们只想要connect函数,不想去实现它。所以,这下react-redux就出现了,react-redux里面,就提供了connect函数,直接使用即可。
import { connect } from 'react-redux';
是不是 very happy。
并在react-redux中还提供了Provider的组件(利用useContext实现的),在项目的入口文件处,主组件中提供,在所有的子组件中都能使用。
import {Provider} from "react-redux";
<Provider store={store}>
<App/>
</Provider>
从react16.8以后,hooks的出现,react-redux有提供了两个hooks,用来拿取state和dispatch
import { useSelector, useDispatch } from 'react-redux';
并且useSelector 还可以做性能优化,利用第二个参数的浅层比较。
总结
-
为什么要使用react-redux?
封装了一些使用redux的通用逻辑,可以直接调用API
-
react-redux为开发提供了什么?针对类组件 :
connect函数,Provider组件针对函数组件:
useSelector,useDispatch两个hooks,Provider组件