前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >React 带属性 + Redux connect() 的高阶组件正确 Typing 方式

React 带属性 + Redux connect() 的高阶组件正确 Typing 方式

原创
作者头像
Power
发布2023-06-01 16:05:51
5450
发布2023-06-01 16:05:51
举报
文章被收录于专栏:源码库源码库源码库

考虑这样的一个场景。我们有一个高阶组件 WrappedComponent,它接受一个属性类型为 BaseProps 的组件 Component,然后做以下事情:

  • WrappedComponent 的属性类型为 WrappedComponentProps
  • 向其中注入新的属性,属性类型为 InjectedProps
  • 将该组件与返回值类型为 IStatePropsmapStateToProps、类型为 IDispatchPropsmapDispatchToProps 连接 (connect)
  • 在生命周期中添加一些可复用的逻辑

当我们用 JS 的时候,上面的需求很简单:

import React from 'react';
import { connect } from 'react-redux';

import { increaseCount } from './actions';

const withPropsAndConnect = (Component) => {
  const injectedProps = {
    /* Injected props */
  };

  class WrappedComponent extends React.Component {
    componentDidUpdate() {
      /* ....... */
    }

    render() {
      const childProps = {
        ...injectedProps,
        ...this.props
      };
      return <Component {...childProps} />
    }
  }

  const mapStateToProps = (state) => {
    return {
      count: state.rootReducer.count,
      // redux mapStateToProps
    };
  };

  const mapDispatchToProps = {
    increase: () => increaseCount()
  };

  return connect(mapStateToProps, mapDispatchToProps)(WrappedComponent);
}

然而,当我们用 typescript 的时候,这件事就变得十分地麻烦,反正我看着一整页的 typescript 报错,脑子里只有 “ybb”:

image.png
image.png

经过了一整个晚上的冲浪,终于找到了正确的写法。这里需要借助 utility-types 包的工具泛型 Diff<U, T>

import React from 'react';
import { connect } from 'react-redux';
import { Diff } from 'utility-types';

import { increaseCount } from './actions';
import { AppState } from './store/types';         // redux store 状态树类型

export const withPropsAndConnect = <BaseProps extends object>(Component: React.ComponentType<BaseProps>) => {
  const mapStateToProps = (state: AppState) => ({
    count: state.rootReducer.count,
  });
  const mapDispatchToProps = {
    increase: () => increaseCount()
  };

  const injectedProps: InjectProps = {
    // ...
  };

  type IStateProps = ReturnType<typeof mapStateToProps>;
  type IDispatchProps = typeof mapDispatchToProps;

  type ComponentProps = IStateProps & IDispatchProps & WrappedComponentProps;
  type ComponentState = WrapperBaseStates;

  class WrappedComponent extends React.Component<ComponentProps, ComponentState> {
    constructor(props: ComponentProps) {
      super(props);
  
      this.state = { /* ... */ };
  
    componentDidUpdate(prevProps: ComponentProps) {
      /* ... */
    }
  
    render() {
      const childProps = {
        ...injectedProps,
        ...this.props
      };
      return (
        <Component
          {...(injectedProps as BaseProps)}
        />
      );
    }
  }

  type HOCProps = Diff<BaseProps, object>;

  return connect<IStateProps, IDispatchProps, HOCProps, AppState>
      (mapStateToProps, mapDispatchToProps)(WrappedComponent);
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档