-
-
Notifications
You must be signed in to change notification settings - Fork 15.3k
Graphical Cheat Sheet #2254
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Looks cool. Do you have that as a "source" file of some sort? E.g., LaTex or SVG |
There's also the "diagrams" thread over in #653 . Would be nice if we could fit a couple of those in somewhere useful (particularly the neat animated gifs from the "Twitter Hype to Production" slideshow). |
@uanders Very nice!
...committing the comments for now. |
|
|
|
|
Thanks all for the fast responses and the 👍. It shows how important graphics are and how much easier they are to understand in comparison to text. Let me go through the comments one by one: @timdorr Sorry, it's been made with a graphics program, therefore only png, no LaTeX, no SVG. @sompylasar Thanks for all your suggestions:
So, here comes the new Cheat Sheet. Further comments welcome! |
Right, but:
|
Maybe a misunderstanding here. Here's what I suggest, and that perfectly follows your logic: "On click, dispatch a command.": <SmartComponent01 />
dispatchOnClick() {
const payload = { /* ... */ };
this.props.dispatch(actionC(payload));
}
<DumbComponent01 onClick={this.dispatchOnClick} />
render() {
<input type="checkbox" onClick={this.props.onClick} />
} Imagine your DumbComponent01 has two buttons, each has to have its own handler: <SmartComponent01 />
dispatchFirst() {
const payload = { /* ... */ };
this.props.dispatch(actionFirst(payload));
}
dispatchSecond() {
const payload = { /* ... */ };
this.props.dispatch(actionSecond(payload));
}
<DumbComponent01 onFirstClick={this.dispatchFirst} onSecondClick={this.dispatchSecond} />
render() {
<button type="button" onClick={this.props.onFirstClick}>{'First'}</button>
<button type="button" onClick={this.props.onSecondClick}>{'Second'}</button>
} This approach allows to test function alertFirst() { alert('first'); }
function alertSecond() { alert('second'); }
<DumbComponent01 onFirstClick={alertFirst} onSecondClick={alertSecond} /> |
Unfortunately, "dispatch() gets an actionCreator as an argument." and "Of course dispatch() executes the actionCreator function" are wrong statements. dispatch(actionC(...)); // dispatch gets *the return value* of actionCreator as an argument
// versus
dispatch(actionC); // dispatch gets actionCreator as an argument dispatch(actionC(...)); // this line is executed as follows:
// 1: const theObjectReturnedFromActionC = actionC(...) // `actionC` is called, returns an action object
// 2: dispatch(theObjectReturnedFromActionC) // `dispatch` is called with what's been just returned from `actionC(...)` So, |
Note the difference between This comment was not about the payload, it was about differentiating between passing a reference to a function and passing a return value of a function call. By the way, what's hidden behind the |
Sorry, I didn't notice the I agree with having slices as a typical setup and naming them alike subreducer names. I don't believe |
Skimming through this, I would generally back up everything that @sompylasar has said so far. I definitely don't see any reason to bring routing into this, and it's probably better to leave Immutable.js out of it as well. |
Of course you can use whatever conventions you want, but I believe naming the prop for your dumb components Besides that, there are a couple of other reasons:
|
Well, thanks again, for the feedback and especially @sompylasar for the amount of QA and explanations you have provided. @sompylasar I have no problem admitting, that I agree with all you comments. Also, I apologize I have not been exact when I was referring to the actionCreator in terms of return object vs call by reference. But I believe it was correctly expressed in the Cheatsheet. So, I now assume that I have reflected all comments from @sompylasar and @naw in the new version 1.0.2. Please let me know otherwise. @sompylasar, I have not understood, why you are suggesting something else then what follows, so this may be the only (?) point open: dispatchOnClick() {
/* ... */
const payload = { /* ... */ }
this.props.dispatch(actionC(payload))
} I have been thinking of how to address your recommendations, to take 'immutable' and 'react-router' out. (I think 'react-router-redux' is not required when using 'react-router' in a Redux environment). As I mentioned in the beginning the Cheatsheet is also going to be part of an article. But in the end I have decided that I can always use an "extended" version for the article and leave a core version here. So here is the next version: |
Yes, looks like now it's clear. Just noticed one more typo: "makeSameCalculations" should probably say "sOme", not "sAme".
What I'm trying to explain here is that what you pass into I'd also rephrase "connect() instantiates new component" to say "rendered by component made by connect()" because in React world seems nobody says instantiate because "component" is assumed to be a class, but instance of a component is "element", not "component instance". |
Isn't this how actionCreators are defined in Redux? I have just replaced 'text' in the example with the more general term 'payload'? I am not saying that 'payload' is an action object. |
You're right. But we're trying to make things simpler for the readers. This implies not calling different things with the same word. The "payload" word has vague meaning. In the Flux world (Redux is part of it) the word "payload" has been reserved to designate the "additional" data that goes along the action type in the action object. But I am referring to this part:
There is a recommended shape of action objects called "flux standard action" which is: {
type: 'ACTION_SOMETHING_HAPPENED',
payload: {
// Some info about action.
what: 'something',
when: 14567893456,
},
meta: {
// Some info about dispatch.
dispatchStatus: 'OK',
},
} In that recommended shape, the "payload" is the exact object that goes into the created action. But action creators do not necessarily take that object as an argument. They can take a subset of that payload, or something different that helps to make the actual payload function messagePosted(userId, text) {
return {
type: 'ACTION_MESSAGE_POSTED',
payload: {
messageId: Math.random(), // bad example of id creation
messageText: text,
userId: userId,
},
};
} |
I'd like to add that in my redux apps I do not use actionCreators at all, I have a generic one that makes a flux standard action out of three arguments. But that's me, not the commonly recommended way. I use redux-saga so I don't need logic inside action creators, and generally the same action is dispatched from one or a few places so this does not make sense to abstract into a function. import serializeError from 'serialize-error';
import assert from 'assert';
/**
* Makes a "flux standard action" object.
*
* The `payload` and `meta` are made serializable.
*
* @param {string} type Action type.
* @param {*} [payload] (optional) Action payload.
* @param {*} [meta] (optional) Action metadata.
* @return {{type:string,payload:*,meta:*}} A "flux standard action" object.
*/
export default function makeAction(type, payload, meta) {
assert((type && typeof type === 'string'), 'makeAction: `type` is not a string.');
// NOTE(@sompylasar): Cloning `payload` and `meta` to not be afraid to put `Error` objects in them.
// NOTE(@sompylasar): Using `serializeError` to clone because it can kill circular references.
return {
type: type,
payload: ( payload && typeof payload === 'object' ? serializeError(payload) : payload ),
meta: ( meta && typeof meta === 'object' ? serializeError(meta) : meta ),
};
} |
Exactly. "payload" is the additional information that goes alongside the type as shown under Actions in the Cheatsheet. And this is exactly what I have tried to express. Your example reads: function messagePosted(userId, text) {
return {
type: 'ACTION_MESSAGE_POSTED',
payload: {
messageId: Math.random(), // bad example of id creation
messageText: text,
userId: userId,
},
};
} I have tried to express this with a general interface to an actionCreator const payload =
{
messageId: Math.random(), // bad example of id creation
messageText: text,
userId: userId,
}
function messagePosted(payload) {
return {
type: 'ACTION_MESSAGE_POSTED',
// payload: payload
payload // ES6
};
} |
@uanders What you've described is a very "special" case, not the general case at all. It is definitely not generally true that action creators receive a single argument and return it verbatim as the payload key of the action object. There are three simplifications you've made:
In a typical redux app, none of those are true, so you don't want your chart to reinforce such ideas. Of course, some simplifications are acceptable in a chart, but the particular simplifications you've chosen could give beginners the wrong impression. |
@naw I think it is impossible to describe the general case in a Cheatsheet of one page, so there is always a compromise. I think the general case is well described in the doc. The main focus of the Cheatsheet is to go one full circle and show the mechanism. It does not claim at all that actionCreators are always constructed the way it is shown here. The ideas I am trying to get across are:
I don't feel, that the Cheatsheet is claiming at all that actionCreators only take a single argument. This is just the solution chosen here for brevity. However, to understand what you would suggest instead, would you prefer to have something like this? //ActionCreators
actionA(id)
actionB(text)
actionC(payload)
//Actions
{type: ACTION_A,
id}
{type: ACTION_B,
text}
{type: ACTION_C,
payload} |
Ok, I see now that you're using payload as a stand-in for a specific thing like I would use Perhaps something like this. actionA(foo)
actionB(bar)
actionC(foo, bar)
{ type: ACTION_A, foo, ...otherStuff }
{ type: ACTION_B, foo: bar.foo }
{ type: ACTION_C, fooBars: [foo, bar] } |
@naw, thanks for the suggestion:
I started to put it into the Cheatsheet, but then I had to change to much and suddenly I felt, that I was losing consistency and had to explain too much. So, I turned it back. Your suggestion is certainly more general than to just use a payload, but I am hesitant. Personally. --- and even though it is less general --- I find it much easier to understand and explain that everything necessary to compute the new state slice is sitting in a payload object. At least I find this a much clearer approach than to have a different interface for every actionCreator, where there is no space to explain this. But again, I am not suggesting, that this is generally a must, it is just one viable option. Furthermore, I still do not see the principal difference between @sompylasar's makeAction: function makeAction(type, payload, meta) and "my" way of using an actionCreator with regard to the payload argument: function createAction(payload) Both functions have payload as a parameter, which has to be preloaded with everything that is necessary to compute the new state. I see a lot of advantages in always having the same payload argument per actionCreator and have some difficulties to see why you are objecting to this so much apart from being less general. The upside is that it is much more consistent on a one page Cheatsheet. For the time being, I leave you the latest version with the error corrections and brood a little more over your suggestions with respect to payload. Thanks a lot so far. |
It's perfectly fine to have specialized conventions within a given application. If you want all of your action creators to have an argument literally named One thing you'll want to ask yourself is whether you are building a cheat sheet for react-redux in general, or a cheat sheet for your own conventions. If I were to build a cheat sheet, it would likely look a lot different than this, and that's OK because diversity in educational tools is good for the community. Please feel free to move forward with what seems best to you. I don't think there are any glaring errors. With that said, one small thing I would change is the wording for "also providers connect() function to content of ". |
I'm good with the latest version (1.0.3) if the @naw 's note is fixed:
But it actually provides the store object itself, not its pieces, via React context (in fact, it provides anything that you pass to its store prop). Use the Force, read the source please https://github.com/reactjs/react-redux/blob/ac01d706dd0b0542a0befd9cd5869c96cd2314dc/src/components/Provider.js#L29 |
I stand corrected. I did look at the source, but I was mistakenly under the impression that childContextTypes and store shape limited what actually ended up in context. I guess I'm dumber than I look. 😄 |
RE: #2254 (comment) Just for info, both propTypes, childContextTypes and contextTypes are meant to be development-only hints, and they should not change what actually gets passed down. I'm not sure though (looked up before but forgot) if the top-level keys of |
EDIT Fixed according to #2254 (comment) thanks @naw And looked it up, |
1.0.4 LGTM 👍 |
Sorry this is a little off topic now, but I would appreciate some clarification on @sompylasar my impression is that you do have to define the top-level keys for context in Am I mistaken? |
@naw Yes, my bad, haven't noticed that these aren't under Edited the original comment #2254 (comment) |
@naw, @sompylasar, @markerikson: I have put the final cheatsheet into its own repo: https://github.com/uanders/react-redux-cheatsheet There you will also find the "extended" version of the cheat sheet with 'immutable" and 'react-router' added. Furthermore, there is the accompanying article which I may post on Medium if it has been quality assured after some time. Feel free to comment on the article as well if you like. I think your comments made this cheat sheet way better.... |
I have put together a graphical cheat sheet for Redux. I am happy to PR it to Redux should there be interest. I believe it will help people to find their way through the concept & workflow.
I am also going to publish it shortly, probably on Medium with an accompanying article. Should you find any errors, please let me know. Thanks.
The text was updated successfully, but these errors were encountered: