redux-logic icon indicating copy to clipboard operation
redux-logic copied to clipboard

redux-logic + flow best practice?

Open ghost opened this issue 9 years ago • 5 comments

Hi,

Currently I'm struggling with the use of Flow in combination with redux-logic because Flow does not understand that a given logic will only receive actions of a given type.

Given the following types:

export type Action =
          { type: 'SEARCH_LOCATION_SELECT', payload: string }
          | { type: 'GEOLOCATION_REQUEST' };

export type Dispatch = (action: Action) => any;

export type LogicContextT = {
  action: Action,
  getState: () => GlobalState
}

This is a problem for Flow:

const aroundMeSelectLogic = createLogic({
  type: 'SEARCH_LOCATION_SELECT',
  process({ action }: LogicContextT, dispatch: Dispatch): void {
    if (action.payload === 'AROUND_ME') {
      dispatch(geolocationRequest());
    }
  }
});

property payload. Property not found in object type

and this is NOT a problem for Flow:

const aroundMeSelectLogic = createLogic({
  type: '*',
  process({ action }: LogicContextT, dispatch: Dispatch): void {
    if (action.type === 'SEARCH_LOCATION_SELECT' && action.payload === 'AROUND_ME') {
      dispatch(geolocationRequest());
    }
  }
});

Does anyone have a suggestion on how to best handle this?

ghost avatar Oct 28 '16 12:10 ghost

Would a work around be to define a payload for the other action too?

I'm sure there is a better way, but I wonder if that would work.

jeffbski avatar Oct 28 '16 20:10 jeffbski

I believe I found a discussion of the same problem over in an issue on the redux repo, maybe there will be some ideas in there.

https://github.com/reactjs/redux/issues/290

jeffbski avatar Oct 28 '16 21:10 jeffbski

It looks like this PR was the result of many discussions for the flow types for Redux. It has a union of actions, so maybe this provides some clues on how to proceed. I wish I understood Flow better to be able to provide some guidance, but I am not there yet.

jeffbski avatar Oct 28 '16 21:10 jeffbski

Hi @jeffbski

Thanks for taking the time to reply.

Adding payload to all actions would not solve it since the payload might be different from action to action, it might solve the example I gave but then fail when I tried to access a property in a payload that was an object and not a string. Also, I might be listening for actions from 3rdparty libs which I don't control the action shape (eg. react-router-redux).

I am not sure what code you are exactly pointing to, but indeed a union of actions + polymorphic types can solve the issue, although things get a bit more verbose.

This is not a problem for Flow and is the best approach I can currently come up with :

export type SearchLocationSelectAction = { type: 'SEARCH_LOCATION_SELECT', payload: string };
export type GeolocationRequestAction = { type: 'GEOLOCATION_REQUEST' };

export type Action = SearchLocationSelectAction | GeolocationRequestAction;

export type Dispatch = (action: Action) => any;

export type LogicContextT<A> = {
  action: A,
  getState: () => GlobalState
}

const aroundMeSelectLogic = createLogic({
  type: 'SEARCH_LOCATION_SELECT',
  process({ action }: LogicContextT<SearchLocationSelectAction>, dispatch: Dispatch): void {
    if (action.payload === 'AROUND_ME') {
      dispatch(geolocationRequest());
    }
  }
});

ghost avatar Oct 29 '16 11:10 ghost

@ivoanastacio Thanks for posting the polymorphic approach.

As I learn Flow better I'll post back any other ideas I come up with, but this seems to be the best way to go for the moment. I too wish it wasn't so verbose.

jeffbski avatar Oct 29 '16 18:10 jeffbski