彻底搞懂React-redux
滴水能把石穿透,万事功到自然成—zZ先森
一张图搞懂Redux运行原理
前言
众所周知,不管是react-redux还是vuex,都是参考于redux的公共状态管理机制。那么搞清楚redux的运行原理,也就搞明白了俩大视图框架的公共状态的一个管理模式。接下来,让我们探究一下它到底是如何做到的。
概括Redux的运行原理
看到首图很懵吧?首先,以我的理解,先概括一下上图所表达的Redux运行原理。
创建一个仓库: 创建仓库,用来存储和管控公共状态。
不难理解,管理公共状态,首先得给他找个地方存储,我把它称为仓库。仓库里有俩个地方分别存放了状态和修改状态的事件,称为状态池和事件池,仓库并提供了操作状态和事件的方法。
- 通过
store.getState()
获取仓库中的状态
各个组件通过此方法获取用到的公共状态,作为渲染视图的数据。
reducer
充当了仓库的管理角色,每个组件操做状态都得通过reducer。
reducer
作为英文单词是减速器、缩减者的意思。在这里的意思是操作状态,管理行为,让组件更加有秩序地、有规则地从仓库里获取状态信息。reducer是一个函数,有俩个参数分别是:【state】【action】,在接收组件dispatch传递进来的行为对象,传递给action,进而做相应的处理。action是一个对象,并保证type
属性的存在,用来识别该行为。state携带的就是仓库的初始数据,仓库只不过是给reducer提供一个存储数据的地方。通过对action的操作返回最新修改后的状态信息,同时把仓库中的状态修改了。
- 通过
store.subscribe()
往仓库的事件池中订阅方法
各个组件为了后期能获取到最新的状态,提前向组件中订阅修改自己状态的方法,一旦仓库中的状态改变,组件会重新渲染。
store.subscribe()方法执行的返回值是从事件池中移除方法的函数:unsubscribe()
- 通过
store.dispatch()
派发一个任务告知reducer修改仓库中的状态。派发的就是一个带有type
的对象,通过type
来标识修改哪个状态。
最后各个组件都能有效的实时更新,实现了公共状态的管理以及各个组件之间的通信。
手写Redux源码以及优化
- 提供五个方法
dispatch
subscribe
getState
replaceRedecer
[$$observable]:observable
- Redux源码优化
用户使用getState,克隆一份新的状态,防止直接修改
对于添加事件池中,做去重处理
防止在reducer中直接修改状态
克隆一份新的状态,并返回
我们知道确实是通过派发任务通知reducer去修改状态,但是我们在操作状态的时候为了能一次性更新,且在修改的时候不破坏原有的状态,防止造成状态的混乱,有必要克隆一份新的状态。在我们使用reducer的时候,也是新克隆一份。
- 深克隆(推荐)
JSON.parse(JSON.stringify(xxx))
对于状态没有更新,我们不通知事件池中的方法执行,从而提高性能。用深比较。
//优化一 深克隆exportcloneDeep(obj){
if(obj===null) return null;
if(typeof obj!=="function") return obj;
if(obj instanceof RegExp) return new RegExp(obj);
if(obj instanceof Date) return enw Date(obj);
letclone = new obj.constructor;
Object.keys(obj).forEach(item=>{
clone[item] = cloneDeep(obj[item])
})
returnclone
}
exportfunction createStore(reducer){
if(typeof reducer!=="function"){
throw new TypeError("Expected the reducer to be a function ")
}
//state存放状态 listener
存放事件池
let state,
isdispatch =false;
listeners = [];
//获取状态
getState(){
//优化一:把返回的信息进行深克隆,这样读取到的状态信息,不能直接基于对象.xx修改了
returncloneDeep(state)
}
//向事件池中追加方法
function subscribe(func){
if(typeof!=="function"){
throw new Error('Expectted the listener to be a function ')
}
//优化二
if(!listeners.includes(func)){
listeners = listeners.push(func);
}
returnfunctionunsubscribe(){
listeners.filter(item=>{
item!==function
})
}
}
//派发任务
function dispatch(action){
if(func===null||typeof action!=="object"){
throw new Error(
'Action must be plain objects.'+'Use custom middleware for async actions'
)
}
if(typeof action === 'undefined'){
throw new Error(
'Action may not have an undefined 'type' property'+'have you misspelled a constant?'
)
}
//优化三 防止在reducer中修改状态,不用用户自己手动克隆state,这里可以深克隆一下
let preState = state;
state = reducer(state,action);
//优化四 深比较 没有修改则不通知listeners中的方法执行
if(!compareDeep(preState,state){
listeners.forEach(item=>{
item();
})
}
}
//默认创建store 就执行一次dispatch 目的是给状态赋初始值
dispatch({
//不能和后期用户的action.type冲突
type:Symbol('INIT')
})
return {
setState,
subscribe,
dispatch
}
}
//优化四 深比较
export compareDeep(val1,val2){
lettype1 = typeof val1,
type2 = typeof val2;
if(type1===null&& type2===null){
returntrue
}
if(type1==="function"&&type2==="function"){
return val1.toString === val2.toString
}
if(type1==="object"&&type2==="object"){
let ct1 = val1.costructor,
ct2 = val2.constructor;
if((ct1===RegExp&&ct1===RegExp)||(ct2===Date&&ct2===Date)){
return val1.toString() === val2.toString()
}
let key1 = Object.keys(val1),
key2 = Object.keys(val2);
if(key1.length===key2.length){
key1.forEach(item=>{
let value1=val1[item],
value2=val2[item];
let res = compareDeep(value1,value2);
if(!res) return res
})
}
returnfalse;
}
//基本数据类型 直接基于三个等于号比较即可
return val1===val2
}
React-redux
React-redux是React基于Redux封装的状态管理库,基于Redux,它做了以下三个大事情:
- 提供Provider祖先组件,把store仓库放置到上下文中供子组件调用
- 提供connect方法,将状态通过属性的方式挂载到子组件上。把action-creator返回的对象类型转换为dispatch派发格式,并通过属性挂载到子组件上。
- 返回的是代理组件(也是一个函数)把当前需要代理的组件作为参数放到返回的函数中即可,会帮我们给redux容器中的事件池中添加一个“公共状态改变能够重新渲染的事件方法。
思维导图:
React-redux部分源码
import React from 'redux';import PropTypes from 'prop-types';
const ThemeContext = React. creatContext();
export class Provider extends React.Component{
static propTypes = {
store:PropTypes.object.isRequired
};
render(){
<ThemeContent value={
{
store:this.props.store
}
}>
//真实要渲染的组件拿过来渲染
{this.props.children}
</ThemeContent>
}
}
exportfunction connect(mapStateToProps,mapDispatchToProps){
//初始化参数
if(typeof mapStateToProps!=="function"){
mapStateToProps = state=>{
return{}
}
}
if(typeof mapDispatchToProps!=="function"){
if(mapDispatchToProps!==null&& typeof mapDispatchToProps==='object'){
let action = mapDispatchToProps;
mapDispatchToProps = dispatch=>{
let obj = {};
Object.keys(action).forEach(item=>{
obj[item] = (...args)=>{
dispatch(action[item](...args))
}
})
return obj;
}
}
mapDispatchToProps = dispatch=>{
return{}
}
}
returnfunction connectHOC(component){
return class proxy texends React.Component{
static contextType = ThemeContext;
render(){
return <component/>;
}
queryPros=()=>{
let { store } = this.conext,
state = store.getState(),
dispatch = store.dispatch;
return {
...mapStateToProps(state);
...mapDispatchToProps(dispatch)
}
}
componentDidMount(){
this.context.store.subscribe(()=>{
this.forceUpdate();
})
}
}
}
}
结合使用中间件
总结
- 掌握Redux原理
- 掌握React-redux运行原理
- 配合使用中间件
以上是 彻底搞懂React-redux 的全部内容, 来源链接: utcz.com/a/27901.html