【问题标题】:Shorter way to mapDispatchToProps using React, Redux and TypeScript?使用 React、Redux 和 TypeScript 映射DispatchToProps 的更短方法?
【发布时间】:2017-09-05 12:28:47
【问题描述】:

我试图弄清楚在同时使用 React、Redux 和 TypeScript 时如何减少样板文件的数量。在这种情况下您可能无法做到,但想看看是否有人有想法。

我目前有一个组件,它调度一个切换菜单的操作,在显示和隐藏之间交替。为此,我定义了类似这样的类(省略与状态相关的代码,专注于动作的调度):

import {Action, toggleMenu} from "../../actions/index";    

interface IConnectedDispatch {
  toggleMenu: (isActive: boolean) => Action;
}

class HeaderMenu extends React.Component<IOwnProps & IConnectedState & IConnectedDispatch, any> {

  constructor(props: IOwnProps & IConnectedState & IConnectedDispatch) {
    super(props);
    this.toggleMenuState = this.toggleMenuState.bind(this);
  }

  public render() {        
    return (
      <button className={buttonClass} onClick={this.props.toggleMenu(this.props.isActive)} type="button">
      </button>
    );
  }
}

const mapDispatchToProps = (dispatch: redux.Dispatch<Store.All>): IConnectedDispatch => ({
  toggleMenu: (isActive: boolean) => dispatch(toggleMenu(isActive))});

动作被定义为

export function toggleMenu(isActive: boolean): Dispatch<Action> {
  return (dispatch: Dispatch<Action>) => {
    dispatch({
      isActive,
      type: "TOGGLE_MENU",
    });
  };
}

感觉应该可以减少实现我的目标所需的代码量。作为 React、Redux 和 TypeScript 的新手,我不知道究竟是怎么回事。具体来说,一遍又一遍地写动作名称toggleMenu感觉非常重复。例如这部分的两次:

const mapDispatchToProps = (dispatch: redux.Dispatch<Store.All>): IConnectedDispatch => ({
  toggleMenu: (isActive: boolean) => dispatch(toggleMenu(isActive))});

感谢任何建议!

【问题讨论】:

    标签: reactjs typescript redux


    【解决方案1】:

    有一个更短的方法。您可以简化很多代码。

    动作 - 原创

    export function toggleMenu(isActive: boolean): Dispatch<Action> {
      return (dispatch: Dispatch<Action>) => {
        dispatch({
          isActive,
          type: "TOGGLE_MENU",
        });
      };
    }
    

    动作 - 减少

    export const toggleMenu = (isActive: boolean) => ({
      isActive,
      type: "TOGGLE_MENU"
    })
    

    属性接口 - 原始

    interface IConnectedDispatch {
      toggleMenu: (isActive: boolean) => Action;
    }
    

    属性接口 - 简化

    import { toggleMenu } from "./actions"
    interface IConnectedDispatch {
      toggleMenu: typeof toggleMenu
    }
    

    MapDispatch - 原创

    const mapDispatchToProps = (dispatch: redux.Dispatch<Store.All>): IConnectedDispatch => ({
      toggleMenu: (isActive: boolean) => dispatch(toggleMenu(isActive))});
    

    MapDispatch - 减少

    const mapDispatchToProps = { 
      toggleMenu 
    };
    

    我可以推荐这个库typescript-fsa。它有助于减少由操作创建的大量样板,尤其是异步操作。

    【讨论】:

    • 太棒了!谢谢@niba!
    • @niba 你怎么称呼connect?除非我将mapDispatchToProps 声明为const mapDispatchToProps = (dispatch): IConnectedDispatch =&gt; { toggleMenu },否则connect 不会为我正确推断类型。我会用export default ReactRedux.connect(mapStateToProps, mapDispatchToProps)(HeaderMenu);... 来称呼它
    • 我不使用标准的connect。我在connect 周围有我的特殊包装器,它自动从mapStateToPropsmapDispatchToProps 检索类型,我可以稍后将它们放入我的容器定义中。无论如何,我只是尝试做connect(state =&gt; state, { ...actions})(Component);,我没有看到任何问题。您的连接无法正确推断出哪些类型?
    • @niba 当我删除一些显式类型时,我从 react-redux 收到类型错误,例如:this gist
    • @mikebridge 它不起作用,因为您输入错误,您应该将getCityInformation: typeof getCityInformation; 添加到IHomePageDispatchProps
    【解决方案2】:

    mapDispatchToProps 将接受动作创建者的对象而不是函数,并自动将它们全部绑定到dispatch

    From the docs:

    如果传递了一个对象,则假定其中的每个函数都是 Redux 动作创建者。具有相同函数名称但每个动作创建者都封装在 dispatch 调用中以便可以直接调用它们的对象将被合并到组件的 props 中

    这允许您将其重写为:

    const mapDispatchToProps = { 
      toggleMenu 
    };
    

    注意:我不确定你需要在打字稿中输入什么(如果有的话)。

    【讨论】:

    • Dan Abramov 有一个关于这种速记语法 here 的视频。
    猜你喜欢
    • 2020-02-25
    • 2021-08-31
    • 2020-11-15
    • 2019-12-03
    • 2018-12-04
    • 2019-04-28
    • 2021-11-22
    • 2020-12-02
    • 1970-01-01
    相关资源
    最近更新 更多