ethul / purescript-react-redux

MIT License
15 stars 6 forks source link

Question: dispatch signature #5

Open BartAdv opened 7 years ago

BartAdv commented 7 years ago

Hi,

I'm having troubles figuring out why exactly the type of dispatch is polymorphic over f: f action -> f action. Does it has anything with middleware? If so, how could I put it to greater use? Async actions?

Currently in my code I've got couple of invocations like void $ dispatch $ pure $ Login $ Login.AttemptLogin $ LoginData { username: mail, password } and f is mostly inferred to be (redux :: REDUX | eff) for all eff.

ethul commented 7 years ago

When I started working on this, I was experimenting a bit and giving some flexibility in the types since I wasn't precisely sure how I would ultimately end up using this representation. I agree that f is mostly going to be Eff, but I suppose the intention is to have f free to be other MonadEff instances in case the user requires the ability to dispatch an action in a monad besides Eff. An example you mentioned could be when using Aff.

BartAdv commented 7 years ago

OK, but how about the fact it's not merely an f Action, it is a f Action -> f Action?

BartAdv commented 7 years ago

Let's discuss with example:

    render dispatch this = do
      props <- React.getProps this
      pure $ loginView { onClick: \({ mail, password }) -> do
                                                             log "test"
                                                             void $ dispatch $ pure $ Login $ Login.AttemptLogin $ LoginData { username: mail, password }
                       , enabled: not props.inProgress && isNothing props.authData }

Here, f becomes:

Eff                                     
  ( "props" :: ReactProps               
  , "refs" :: ReactRefs (() :: # Effect)
  , "state" :: ReactState               
                 ( "read" :: Read       
                 )                      
  , "console" :: CONSOLE                
  , "props" :: ReactProps               
  , "refs" :: ReactRefs                 
                ( "read" :: Read        
                )                       
  , "state" :: ReactState               
                 ( "read" :: Read       
                 , "write" :: Write     
                 )                      
  | t0                                  
  )                                     

Now, the type of the render is:

type Render props state eff f action = (f action -> f action) -> React.Render props state eff

this means, our dispatch now works within the Eff that's provided by the onClick handler. So far so good, but now I'm feeding it with pure $ Login .... and that probably always is going to be pure, because if I want any effects I can do this in the onClick handler.

Therefore, I think the signature Action -> f Action could be more appropriate. But then I'm not sure why we need to return an Action at all (vanilla redux seems to be doing this, I'm not sure what for, is it only for convenience? Does dispatch always return an action, or can it return something else depending on middleware?)

Alternatively, I guess it would be g Action -> f Action, meaning it should be some effect that would be executed in a context of a store (again, middleware?), but then I'm not sure what could it potentially be.

// EDIT: hmm, maybe current signature makes it more convenient should one employ action creators - it would mean they could be effectful too...

ethul commented 7 years ago

Thanks for the example. I don't really have a strong argument for f Action -> f Action or Action -> Action. I suppose the original idea was to keep things flexible for how actions are obtained. I admit that I have only really been doing void (dispatch (pure action))).

Maybe adding a function createClassEff could be useful where f would be Eff eff?

On the note of returning the action from the dispatch call, I just followed what redux does in this case. Again, I don't have a strong argument for this either way.

BartAdv commented 7 years ago

I suppose I'm gonna leave it as it's now and just wait to gather more use cases.

ethul commented 7 years ago

I think I'd like to reopen this.

I want to explore an idea for how to better utilize the f type.

I will post my thoughts here once I work them out a bit more.