它帮助我们连接 UI 层和数据层。即帮我们合并一些重复操作即获取状态getState
、修改状态dispatch
、订阅更新subscribe
。因此提供了两个核心 API:
Provider
: 接收 store,并将其挂载到 context 上,目的是为了后代组件获取状态Connect
: 将 state、props 传递组件并自动订阅更新本文就核心两个 API 进行分析如下问题:
下面我们根据实现这两个核心功能来逐步揭晓上面的问题。
trySubscribe
)// Context.tsimport React from 'react';export const ReactReduxContext = React.createContext < ReturnType < any >> null;if (process.env.NODE_ENV !== 'production') {ReactReduxContext.displayName = 'ReactRedux';}export default ReactReduxContext;
这里只是简单的采用观察者模式,源码中采用的发布订阅模式。
// Subscription.tsexport default class Subscription<S>{private store:S|any;private listeners:any[]|null;public onStateChange:Function | null | undefined;private unsubscribe:null|any;constructor(store:S){this.store=store;this.unsubscribe=nullthis.listeners=[this.handleChangeWrapper];}//需要组件中设置用来更新组件handleChangeWrapper=()=>{if(this.onStateChange){this.onStateChange()}}//注册监听addListener(listener:any){this.listeners!.push(listener)}//通知更新notify=()=>{this.listeners!.forEach(listener=>{listener()})}//监听storetrySubscribe(){if(!this.unsubscribe){this.unsubscribe=this.store.subscribe(this.notify)}}//取消订阅tryUnsubscribe(){if(this.unsubscribe){this.unsubscribe();this.unsubscribe=null;this.listeners=null}}}
// Provider.tsimport React, { useMemo, useEffect } from 'react';import Subscription from './Subscription';import { ReactReduxContext } from './Context';interface IProps {store: any;context?: React.Context<any>;children: any;}export default ({ store, context, children }: IProps) => {const contextValue = useMemo(() => {const subscription = new Subscription(store);return {store,subscription,};}, [store]);const previousState = useMemo(() => store.getState(), [store]);useEffect(() => {const { subscription } = contextValue;//将 注册组件更新函数(即下文中的onStateChange)subscription.trySubscribe();// if(previousState!==store.getState()){// subscription.not// }return () => {subscription.tryUnsubscribe();subscription.onStateChange = null;};}, [contextValue, previousState]);const Context = context || ReactReduxContext;return <Context.Provider value={contextValue}>{children}</Context.Provider>;};
mapStateToProps
、mapDispatchToProps
方法对包裹组件props
增强onStateChange
,目的为了页面重新渲。props
//Connect.tsximport React, { useContext, useMemo, useState, useEffect } from 'react';import { ReactReduxContext } from './Context';export default (mapStateToProps: Function, mapDisPatchToProps: Function) =>(WrappedComponent: React.ComponentProps<any>) => {return (props: any) => {const { store, subscription } = useContext < any > ReactReduxContext;//设置状态更新state,为了驱动组件更新(newProps更新)const [state, setState] = useState(0);useEffect(() => {subscription.onStateChange = () => setState(state + 1);}, [state]);const newProps = useMemo(() => {const stateProps = mapStateToProps(store.getState());const dispatchProps = mapDisPatchToProps(store.dispatch);return {...stateProps,...dispatchProps,...props,};}, [props, state, store]);return <WrappedComponent {...newProps} />;};};
connect,与我们熟悉的 HOC 都是用到了 装饰器模式
;这种模式可以对组件功能扩展而不必更改原有逻辑(即符合开闭原则)