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 非常重要。

相关推荐
前端Hardy29 分钟前
HTML&CSS:3D图片切换效果
前端·javascript
spionbo1 小时前
Vue 表情包输入组件实现代码及完整开发流程解析
前端·javascript·面试
全宝1 小时前
✏️Canvas实现环形文字
前端·javascript·canvas
lyc2333331 小时前
鸿蒙Core File Kit:极简文件管理指南📁
前端
我这里是好的呀1 小时前
全栈开发个人博客12.嵌套评论设计
前端·全栈
我这里是好的呀1 小时前
全栈开发个人博客13.AI聊天设计
前端·全栈
金金金__1 小时前
Element-Plus:popconfirm与tooltip一起使用不生效?
前端·vue.js·element
lyc2333331 小时前
小L带你看鸿蒙应用升级的数据迁移适配📱
前端
用户26812851066691 小时前
react-pdf(pdfjs-dist)如何兼容老浏览器(chrome 49)
前端