ByAI:Rect-redux实现及connect函数

一、React-Redux 核心原理

  1. ​Provider ​

    通过 React Context 提供 Redux store 给子组件,避免逐层传递 props。

  2. ​connect ​

    高阶组件(HOC)负责:

    • 订阅 store 变化
    • 将 state 和 dispatch 映射为组件的 props
    • 性能优化(避免不必要的渲染)

二、TypeScript 实现

1. 类型定义

typescript 复制代码
import React, { ComponentType, useContext, useEffect, useMemo } from 'react';
import { Store, AnyAction, Dispatch } from 'redux';

// 定义 Connect 的 Props 类型
type OwnProps = Record<string, any>; // 组件自身的 props 类型

// connect 的配置参数类型
interface ConnectOptions<State = any, OP = OwnProps> {
  mapStateToProps?: (state: State, ownProps: OP) => Partial<OP>;
  mapDispatchToProps?: (dispatch: Dispatch<AnyAction>, ownProps: OP) => Partial<OP>;
}

// 连接后的组件 Props 类型
type ConnectedProps<State, OP> = OP & {
  [K in keyof ReturnType<ConnectOptions<State, OP>>]: 
    ReturnType<ConnectOptions<State, OP>>[K];
};

2. Provider 实现

typescript 复制代码
const StoreContext = React.createContext<Store<any, AnyAction> | null>(null);

export const Provider: React.FC<{ store: Store<any, AnyAction> }> = ({ store, children }) => (
  <StoreContext.Provider value={store}>{children}</StoreContext.Provider>
);

3. connect 实现

typescript 复制代码
export function connect<State = any, OP = OwnProps>(
  options: ConnectOptions<State, OP>
) {
  return function <C extends ComponentType<ConnectedProps<State, OP>>>(
    WrappedComponent: C
  ) {
    return function ConnectedComponent(props: OP) {
      const store = useContext(StoreContext);
      if (!store) throw new Error('Missing Provider');

      // 获取当前 state 和 dispatch
      const { getState, subscribe, dispatch } = store;

      // 处理 mapStateToProps
      const mapStateToPropsResult = options.mapStateToProps
        ? options.mapStateToProps(getState(), props)
        : {};

      // 处理 mapDispatchToProps
      const mapDispatchToPropsResult = options.mapDispatchToProps
        ? options.mapDispatchToProps(dispatch, props)
        : { dispatch };

      // 合并 props
      const mergedProps = useMemo(() => ({
        ...props,
        ...mapStateToPropsResult,
        ...mapDispatchToPropsResult
      }), [props, mapStateToPropsResult, mapDispatchToPropsResult]);

      // 订阅 store 变化
      useEffect(() => {
        const unsubscribe = subscribe(() => {
          // 当 store 变化时强制更新组件
          forceUpdate();
        });
        return unsubscribe;
      }, [store]);

      // 强制更新机制
      const [, forceUpdate] = React.useReducer(x => x + 1, 0);

      // 性能优化:仅在相关 state 变化时更新
      const stateSelector = options.mapStateToProps 
        ? (state: State) => options.mapStateToProps(state, props)
        : () => ({});

      const prevSelectedStateRef = React.useRef<any>();
      const shouldUpdate = useMemo(() => {
        const currentSelectedState = stateSelector(getState());
        if (prevSelectedStateRef.current === undefined) {
          prevSelectedStateRef.current = currentSelectedState;
          return true;
        }
        const keys = Object.keys(currentSelectedState);
        return keys.some(key => 
          currentSelectedState[key] !== prevSelectedStateRef.current[key]
        );
      }, [getState, props]);

      useEffect(() => {
        if (shouldUpdate) {
          forceUpdate();
          prevSelectedStateRef.current = stateSelector(getState());
        }
      }, [shouldUpdate]);

      return <WrappedComponent {...mergedProps as ConnectedProps<State, OP>} />;
    };
  };
}

4. 使用示例

typescript 复制代码
// 定义 Redux store 类型
interface AppState {
  count: number;
}

// 定义组件 Props
interface CounterProps {
  count: number;
  increment: () => void;
  decrement: () => void;
}

// 创建组件
const Counter: React.FC<CounterProps> = ({ count, increment, decrement }) => (
  <div>
    <p>Count: {count}</p>
    <button onClick={increment}>+</button>
    <button onClick={decrement}>-</button>
  </div>
);

// 连接 Redux
const ConnectedCounter = connect<AppState, CounterProps>({
  mapStateToProps: (state) => ({
    count: state.count
  }),
  mapDispatchToProps: (dispatch) => ({
    increment: () => dispatch({ type: 'INCREMENT' }),
    decrement: () => dispatch({ type: 'DECREMENT' })
  })
})(Counter);

// 在应用中使用
const App = () => (
  <Provider store={store}>
    <ConnectedCounter />
  </Provider>
);

三、核心机制详解

1. mapStateToProps

  • ​作用​:将 Redux store 的 state 映射为组件的 props

  • ​实现要点​:

    • 接收当前 state 和组件自身 props
    • 返回一个对象,对象的 key 会成为组件的 props
    • 通过浅比较优化更新(避免不必要的渲染)

2. mapDispatchToProps

  • ​作用​:将 dispatch 方法映射为组件的 props

  • ​两种形式​:

    1. 对象形式:{ increment: () => ({ type: 'INCREMENT' }) }
    2. 函数形式:(dispatch) => ({ increment: () => dispatch(...) })
  • ​实现要点​:

    • 自动绑定 dispatch 方法
    • 支持直接传递 action creators 对象

3. 性能优化

  • 订阅机制 :通过 subscribe 监听 store 变化
  • 浅比较:仅当映射后的 state 变化时才触发更新
  • 依赖收集 :通过 useMemo 缓存计算结果

四、与官方实现的差异

  1. 简化了批量更新机制(官方使用 React 的批量更新 API)
  2. 未实现合并 props 的高级功能(如 mergeProps)
  3. 类型系统做了简化(官方有更复杂的泛型处理)

这个实现保留了 React-Redux 的核心功能,同时通过 TypeScript 提供了完整的类型安全支持。实际开发中建议直接使用官方库,但理解其原理对深入掌握 React 和 Redux 非常重要。

相关推荐
8年区块链老兵2 小时前
一篇文章教会你:用区块高度读懂比特币链上的每一笔交易
前端
xixichensh2 小时前
前端转做AI程序员第一步——开发一个AI流式对话Demo
前端
小羊没烦恼!2 小时前
系统内部模块(子系统)之间的耦合以及模块(子系统)划分
java·开发语言·前端·数据库·算法·c#
Leslie1653 小时前
聚合不只是 GROUP BY:HashAggregate 与 SortAggregate 的内存账本
前端
ITOM运维行者3 小时前
PHP性能监控怎么做?从响应时间到慢函数的6个关键指标
前端·javascript·后端
成旭先生3 小时前
AI 文本审核 API:一段中文文本判风险等级、命中标签与处置建议
java·前端·人工智能·api接口·内容风控·文本审核·ugc审核
liangshanbo12153 小时前
前端面试题:AI 对话中超长消息导致内存溢出,怎么解决?
java·开发语言·前端
静默回滚3 小时前
PDF能打开却不能复制,原来是权限密码
前端
律宏阔3 小时前
Dart FFI 内存管理:用 using + Arena 替代嵌套 try-finally
前端·flutter
guslegend4 小时前
脚手架入门:必要性、核心功能与执行原理
前端·架构·node.js·脚手架·前端工程化