reduxjs / redux

A JS library for predictable global state management
https://redux.js.org
MIT License
60.92k stars 15.27k forks source link

Action creators are confusing #746

Closed dminkovsky closed 9 years ago

dminkovsky commented 9 years ago

... at least they are confusing to me.

To me, an action creator is just a helper function that defines an interface for the creation of a certain type of action.

Here's how I would implement "action creators":

1- An abstract action creator:

function createActionAbstract(type, spec) {
    return {
        type: type,
        ...spec
    };
}

2- Concrete action creators wrap the abstract creator:

function createActionAddMessage(spec) {
    assertSomethingAboutSpec(spec);
    return createActionAbstract('ADD_MESSAGE', spec)
}

function createActionDeleteMessage(spec) {
    assertSomethingAboutSpec(spec);
    return createActionAbstract('DELETE_MESSAGE', spec)
}

But how I implement action creators is irrelevant. And how the writer of Redux docs implements them is irrelevant too. Unless they are part of the Redux API, that is. Because otherwise, "action creators" are just helper functions and have nothing to do with Redux.

Unfortunately, the documentation truly doubles down on this concept and uses it all over the place. Every instance of an "action creator" is an added symbols for the reader to grok. Every symbol introduced to an example adds substantial cognitive overhead to the reader. Take for example:

function makeASandwich(forPerson, secretSauce) {
  return {
    type: 'MAKE_SANDWICH',
    forPerson,
    secretSauce
  };
}

function apologize(fromPerson, toPerson, error) {
  return {
    type: 'APOLOGIZE',
    fromPerson,
    toPerson,
    error
  };
}

function withdrawMoney(amount) {
  return {
    type: 'WITHDRAW',
    amount
  };
}

Holy moly, so many symbols for so much detriment.

Can we remove this concept for the documentation? Or formally add it to the API?

gaearon commented 9 years ago

The discussion that led to this issue: https://github.com/gaearon/redux-thunk/issues/17

timdorr commented 9 years ago

Incidentally, @erikras has proposed a solution to a different issue (sprawl of your constants, action creators, and reducers) that would seem to address some of the issues you're having here.

Is the documentation on Actions clear to you? I agree there are inconsistencies with other parts. But that section, if it's sensible, could be used to fix any other areas that are confusing.

What I've found in building my apps on redux is that using concrete action creators is extremely helpful when you go to refactor. Any breakages that happen are explicit and traceable. Actions are themselves abstract, so they can break in hard-to-track ways. By having an explicit, concrete API to my actions, it helps to solidify some of that abstraction and keep the effects of my reducers on state more predictable.

dminkovsky commented 9 years ago

Incidentally, @erikras has proposed a solution to a different issue (sprawl of your constants, action creators, and reducers) that would seem to address some of the issues you're having here.

I've not felt the need for anything like this yet.

Is the documentation on Actions clear to you? I agree there are inconsistencies with other parts. But that section, if it's sensible, could be used to fix any other areas that are confusing.

Yeah it's clear, I would just remove the section about "action creators".

What I've found in building my apps on redux is that using concrete action creators is extremely helpful when go to refactor. [...]

Yes, absolutely. Same here. But that's not because we're using "action creators". No such thing exists in React. What exists, rather, are helper functions that localize the creation of actions to one spot. That's got nothing to do with Redux, but, rather, is a common thing to do across all of programming.

RoyalIcing commented 9 years ago

Maybe the docs need to be pared down to a core, Redux-only guide? And then other guides can be added for 'real-world' use, or 'suggested approaches'?

timdorr commented 9 years ago

Action creators are pretty central to what redux is about, since you want to pass around functions (bound to dispatch) and not expect everyone to know how to create actions spontaneously. Redux uses an object-based action format for communication between the outside environment and the internal behaviors of your reducers on state, but that isn't something you want to concern yourself with. You normally send the action creator's return right into dispatch with no inspection.

Redux doesn't want to enforce an opinion on the shape of your actions, otherwise there would be some sort of callAction function on the store and you would never create actions yourself. However, we should be opinionated about action creators being functions that you create (or generate like a macro) so that we don't encourage bad coding habits that lead to massive law of demeter violations. I want my React component to know when I edit an input, it should call onChange, not that it should create an object with a type field set to some constant I imported. That would get very painful very quickly and would lead to many non-reusable components throughout your app.

Functions are great because they have a concrete signature and you can trace variable usage more easily. Look at your action creator to see which argument was placed into the action in a certain place and then look at how that creator was called. Pretty simple and very important for developer ergonomics with this library.

dminkovsky commented 9 years ago

@BurntCaramel yes that makes sense to me.

@timdorr:

I totally understand all that. However, action creators are not part of the Redux API. There is no function in Redux that accepts or returns action creators.

As @BurntCaramel suggests, using functions that one might call "action creators" is therefore a best practice the one might employ.

However, because action creators are not part of the Redux API, they were confusing to me because I kept expecting to find them somewhere as parameters or return types.

gaearon commented 9 years ago

To be fair there's bindActionCreators utility function that is part of Redux API.

dminkovsky commented 9 years ago

Oh cool! I had totally missed that. Thank you.

timdorr commented 9 years ago

@dminkovsky Does that address the issue at hand? I'm happy to help with improvements on the docs, especially when it comes to consistency. I just want to be sure we're being specific and actionable here. Talking CS theory all day doesn't really move the ball down the field :smile:

dminkovsky commented 9 years ago

@timdorr

Does this address the issue at hand?

I guess so, in the sense that I gather there isn't interest in paring down the docs dramatically. But I would cut them down a lot, beginning with:

Talking CS theory all day doesn't really move the ball down the field

Don't really see this as CS theory. I'm saying the docs contain a lot of irrelevant information that clouds the their purpose: to explain the small and pleasant Redux API.

I feel like I should mention another reason I opened this ticket was because I've noticed a trend in the React community toward this verbose, pedantic style of documentation. I was disturbed to see a tweet a few weeks ago from @knowbody saying that he was inspired by the Redux docs and hoping to emulate them for React Router v1.

But anyway! Despite my immense frustration, I've personally managed to glean what I've needed from the docs and code itself. If I've not succeeded in getting people to agree, that's okay!—given that I'm trying to focus on using Redux as a means to an end, and not a end in and of itself :).

Cheers! and thank you for working on this project.

dminkovsky commented 9 years ago

I've noticed a trend in the React community toward this verbose, pedantic style of documentation.

And by pedantic I mean to the point of extreme ridiculousness. I opened this ticket the same day I read about two-day binding helpers in the React docs, where it says:

In React, data flows one way: from owner to child. This is because data only flows one direction in the Von Neumann model of computing. You can think of it as "one-way data binding."

which is absurd to the max considering:

Yet this stuff crops up all over the React documentation in a way I've seen in no other open source community. Which is weird because the projects themselves are pretty cool.

terraboops commented 9 years ago

I really like the Redux docs and I find their verbosity enlightening.

Sure, I know what Middleware is: a completely overloaded term that means 100 things to 100 people. I am glad that I know what Redux means by Middleware and even happier to know that my understanding coincides with theirs.

As far as Action Creators go, can we just add / enhance the section about them to specify clearly that they are Plain-Old JavaScript Functions? It was clear to me but I read the docs from start to finish instead of as a get-it-done point and click adventure.

And lol @ Von Neumann. On Sep 21, 2015 6:22 PM, "Dmitry Minkovsky" notifications@github.com wrote:

I've noticed a trend in the React community toward this verbose, pedantic style of documentation.

And by pedantic I mean to the point of extreme ridiculousness. I opened this ticket the same day I read about two-day binding helpers in the React docs https://facebook.github.io/react/docs/two-way-binding-helpers.html, where it says:

In React, data flows one way: from owner to child. This is because data only flows one direction in the Von Neumann model of computing. You can think of it as "one-way data binding."

which is absurd to the max considering:

Yet this stuff crops up all over the React documentation in a way I've seen in no other open source community. Which is weird because the projects themselves are pretty cool.

— Reply to this email directly or view it on GitHub https://github.com/rackt/redux/issues/746#issuecomment-142145108.

gaearon commented 9 years ago

Thanks again for the friendly concern!

I totally understand all that. However, action creators are not part of the Redux API. There is no function in Redux that accepts or returns action creators.

As said above, it actually is.

as I mentioned elsewhere, basically everyone coming to Redux probably knows about middleware

I wrote the docs based on the questions people were asking. Middleware is a foreign concept to people who previously wrote client-side Flux applications. This is the prime audience for the docs. Since writing this section, I haven't received many questions about middleware, and I've seen lots of middleware being published, so I assume it actually is helpful.

And if they don't, they don't need to read a Homeric elaboration of middleware that includes terms like "monkeypatching".

It's easily googleable if the term is new, and I've seen it used a lot in JS community.

I feel like I should mention another reason I opened this ticket was because I've noticed a trend in the React community toward this verbose, pedantic style of documentation. I was disturbed to see a tweet a few weeks ago from @knowbody saying that he was inspired by the Redux docs and hoping to emulate them for React Router v1.

I'm sorry you didn't like the docs. I don't know what you mean by the pedantic style—I haven't seen Flux libraries documentations dive into some essential details that I tried to explain here. In my book pedantic is better than incomplete. The docs are sometimes repetetive due to the way they were written, but I'm happy to accept PRs to amend that.

Many people are happy with the docs and claim they learned a ton new things, so maybe it's useful to some, and not so useful to others.

I'm closing as I don't see anything directly actionable here. Please send PRs to help out with the parts you don't like—but these PRs should keep the docs and the flow consistent and better. Moving sections around usually isn't enough—it's better to rewrite the bad parts with the big picture in mind. Thanks!

dminkovsky commented 9 years ago

Thanks @gaearon. Appreciate your thoughtful reply and this thread generally.

What you write makes sense. There audience for these docs is diverse, so they're probably just a bad fit for me.

Let me just beat this horse one final time and say:

A few days ago I wanted to remind myself of how the applyMiddleware function works went to the API docs. For all the prose and examples, for some reason I just couldn't understand what was going on!

Then I remembered that applyMiddleware and compose sources are actually very clear, simple things of beauty. I would say that's what largely frustrates me: at the end of day—and I am not a very experienced developer—I learned all there is to know about Redux by looking at its really nice, clean codebase. I go back to the docs and ask myself: "What? Why? What is all of this? I just want to know how this one function works."

Go figure! It must just me be.

Thank you.

gaearon commented 9 years ago

A few days ago I wanted to remind myself of how the applyMiddleware function works went to the API docs. For all the prose and examples, for some reason I just couldn't understand what was going on!

Then I remembered that applyMiddleware and compose sources are actually very clear, simple things of beauty. I would say that's what largely frustrates me: at the end of day—and I am not a very experienced developer—I learned all there is to know about Redux by looking at its really nice, clean codebase. I go back to the docs and ask myself: "What? Why? What is all of this? I just want to know how this one function works."

If you can make the docs better, make them better in form of PRs.