一、React-Redux 核心原理
-
Provider
通过 React Context 提供 Redux store 给子组件,避免逐层传递 props。
-
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
-
两种形式:
- 对象形式:
{ increment: () => ({ type: 'INCREMENT' }) }
- 函数形式:
(dispatch) => ({ increment: () => dispatch(...) })
- 对象形式:
-
实现要点:
- 自动绑定 dispatch 方法
- 支持直接传递 action creators 对象
3. 性能优化
- 订阅机制 :通过
subscribe
监听 store 变化 - 浅比较:仅当映射后的 state 变化时才触发更新
- 依赖收集 :通过
useMemo
缓存计算结果
四、与官方实现的差异
- 简化了批量更新机制(官方使用 React 的批量更新 API)
- 未实现合并 props 的高级功能(如
mergeProps
) - 类型系统做了简化(官方有更复杂的泛型处理)
这个实现保留了 React-Redux 的核心功能,同时通过 TypeScript 提供了完整的类型安全支持。实际开发中建议直接使用官方库,但理解其原理对深入掌握 React 和 Redux 非常重要。