简体   繁体   English

如何使用流类型绑定异步操作创建者?

[英]How to bind async actions creators using flowtype?

I just started learning flowtype and i need some help to understand two things that aren't clear on my mind. 我刚开始学习流程类型,我需要一些帮助来理解我不清楚的两件事。

  1. Using https://github.com/reactjs/redux/blob/master/examples/todos-flow as an example, i wonder how control over types can work without type definitions of https://github.com/flowtype/flow-typed , in this case: https://github.com/flowtype/flow-typed/blob/master/definitions/npm/redux_v3.xx/flow_v0.33.x-/redux_v3.xxjs ? https://github.com/reactjs/redux/blob/master/examples/todos-flow为例,我想知道如果没有https://github.com/flowtype/flow-的类型定义,对类型的控制如何工作在这种情况下为typedhttps : //github.com/flowtype/flow-typed/blob/master/definitions/npm/redux_v3.xx/flow_v0.33.x-/redux_v3.xxjs

  2. If I use redux definitions, the validation of bindActionCreators fails when i try to bind async action creator (i'm using redux-thunk). 如果我使用redux定义,则当我尝试绑定异步操作创建者时, bindActionCreators的验证将失败(我正在使用redux-thunk)。

How to continue using flow and bind async actions creators when using redux-thunk? 使用redux-thunk时如何继续使用流并绑定异步操作创建者?

Code sample ( https://gist.github.com/momsse/323c228e8c5e264067039b8446cd890f ) : 代码示例( https://gist.github.com/momsse/323c228e8c5e264067039b8446cd890f ):

import { bindActionCreators } from 'redux';
import type { Dispatch } from 'redux';

type Action = { type: 'SET_PROFILE', profile: Object };

/**
 * Based on https://github.com/gaearon/redux-thunk/blob/master/index.d.ts
 */
type ThunkAction = (dispatch: Dispatch<Action>,
                    getState: () => any,
                    extraArgument: any) => any;

type Profile = {
  name: string,
  team: string
}

// Async actions creator
function setProfile(profile: Profile): ThunkAction {
  return dispatch => setTimeout(() => dispatch({ type: 'SET_PROFILE', profile }), 2000);
}

const profileActionCreators = { setProfile };

type Props = {
  actions: {
    setProfile: (profile: Profile) => ThunkAction,
  }
}

function mapDispatchToProps(dispatch: Dispatch<Action>): Props {
  return {
    actions: bindActionCreators(profileActionCreators, dispatch)
  };
}

Errors: 错误:

 40:     actions: bindActionCreators(profileActionCreators, dispatch)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function call. Function cannot be called on any member of intersection type
 40:     actions: bindActionCreators(profileActionCreators, dispatch)
                  ^^^^^^^^^^^^^^^^^^ intersection
  Member 1:
   49:   declare function bindActionCreators<A, C: ActionCreator<A, any>>(actionCreator: C, dispatch: Dispatch<A>): C;
                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ polymorphic type: function type. See lib: flow-typed/npm/redux_v3.x.x.js:49
  Error:
   49:   declare function bindActionCreators<A, C: ActionCreator<A, any>>(actionCreator: C, dispatch: Dispatch<A>): C;
                                                   ^^^^^^^^^^^^^^^^^^^^^ function type. Callable signature not found in. See lib: flow-typed/npm/redux_v3.x.x.js:49
   40:     actions: bindActionCreators(profileActionCreators, dispatch)
                                       ^^^^^^^^^^^^^^^^^^^^^ object literal
  Member 2:
   50:   declare function bindActionCreators<A, K, C: ActionCreators<K, A>>(actionCreators: C, dispatch: Dispatch<A>): C;
                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ polymorphic type: function type. See lib: flow-typed/npm/redux_v3.x.x.js:50
  Error:
   13:   declare type Dispatch<A: { type: $Subtype<string> }> = (action: A) => A;
                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^ property `type` of object type. Property not found in. See lib: flow-typed/npm/redux_v3.x.x.js:13
   21: function setProfile(profile: Profile): ThunkAction {
                                              ^^^^^^^^^^^ function type

These are the full declarations for ActionCreator and bindActionCreators: 这些是ActionCreator和bindActionCreators的完整声明:

  declare type ActionCreator<A, B> = (...args: Array<B>) => A;
  declare type ActionCreators<K, A> = { [key: K]: ActionCreator<A, any> };

  declare function bindActionCreators<A, C: ActionCreator<A, any>>(actionCreator: C, dispatch: Dispatch<A>): C;
  declare function bindActionCreators<A, K, C: ActionCreators<K, A>>(actionCreators: C, dispatch: Dispatch<A>): C;

In your code, bindActionCreators will wrap each property of profileActionCreators in dispatch . 在您的代码中, bindActionCreators会将bindActionCreators每个属性包装在dispatch You seem to be expecting dispatch to be passed to the setProfile function, where dispatch can later be used as a callback. 您似乎期望将分派传递给setProfile函数,在此以后可以将分派用作回调。

But it doesn't seem to me that bindActionCreators supports "binding" dispatch as a callback. 但是在我看来,bindActionCreators支持“绑定”调度作为回调。 Rather, dispatch is "bound" like this: 相反,调度是这样的“绑定”:

function bindActionCreator(actionCreator, dispatch) {
  return (...args) => dispatch(actionCreator(...args))
}

So in your code, it effectively looks like this: 因此,在您的代码中,它实际上如下所示:

function mapDispatchToProps(dispatch: Dispatch<Action>): Props {
  return {
    actions: {
      setProfile: (profile) => dispatch(dispatch => setTimeout(() => dispatch({ type: 'SET_PROFILE', profile }), 2000)),
  };
}

Flowtype is therefore correctly catching the type error, saying that bindActionCreators expects each property of the object to be an actionCreator: () => Action . 因此,Flowtype可以正确捕获类型错误,表示bindActionCreators希望对象的每个属性都是一个actionCreator: () => Action

You probably can't use bindActionCreators for your use case, or you need to rethink how you handle thunks. 您可能无法在用例中使用bindActionCreators,或者您需要重新考虑如何处理重击。 Here is an approach that should work . 这是一种可行的方法

const profileActionCreators = { setProfile };

type Props = {
  actions: {
    setProfile: (profile: Profile) => setTimeout,
  }
}

function mapDispatchToProps(dispatch: Dispatch<Action>): Props {
  const boundActions = bindActionCreators(
    profileActionCreators,
    dispatch
  );
  return ({
    actions: {
      setProfile: (profile: Profile) => setTimeout(() => boundActions.setProfile(profile), 2000),
    },
  });
}

Thunk approach 重击方法

If you want to keep your ThunkAction approach, you won't be able to use bindActionCreators. 如果您想保留ThunkAction方法,将无法使用bindActionCreators。 This also works. 这也有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM