-
Notifications
You must be signed in to change notification settings - Fork 297
Omit payload on undefined only #128
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
Conversation
@yangmillstheory This PR is slightly different than #115. Please have a look at the changes. You'll see that I've only changed a single line to fix the tests. It now looks a bit weird to me, because at some parts in So in the end, only the identity function is affected by this change. Do you think this is overall still correct? I actually thought that we are using This is how I think const TYPE = 'TYPE';
const errorObj = new TypeError('foo')
// 1. Throw an error when payloadCreator is not `undefined` or a function
//
// Returns:
// new TypeError('payloadCreator must be undefined or a function')
const actionCreatorB = createAction(TYPE, 'foo')
// 2. Use identity function when payloadCreator is `undefined`
//
// Returns:
// {
// type: 'TYPE'
// payload: 'foo'
// }
const actionCreator = createAction(TYPE)
actionCreator('foo')
// 3. Use payloadCreator when it is a function
//
// Returns:
// {
// type: 'TYPE',
// payload: {
// a: 'foo',
// b: 'bar'
// }
// }
const actionCreator = createAction(TYPE, (a, b) => ({ a, b }))
actionCreator('foo', 'bar')
// 4. Accept a second parameter as function for adding meta to the object
//
// Returns:
// {
// type: 'TYPE',
// payload: 'foo',
// meta: 'bar'
// }
const actionCreator = createAction(TYPE, (a) => a, (b) => b)
actionCreator('foo', 'bar')
// 5. Omit payload when payloadCreator is `undefined`, but a second parameter has been set for adding meta to the object
//
// Returns:
// {
// type: 'TYPE',
// meta: 'bar'
// }
const actionCreator = createAction(TYPE, undefined, (a) => a)
actionCreator('bar')
// 6. Set `error` to `true` when payload is an Error object and bypass any payloadCreator
//
// Returns:
// {
// type: 'TYPE',
// error: true,
// payload: new TypeError('foo')
// }
const actionCreatorA = createAction(TYPE)
const actionCreatorB = createAction(TYPE, (a, b) => ({ a, b }))
actionCreatorA(errorObj)
actionCreatorB(errorObj)
// 7. Set error to true when payload is an Error object and bypass any payloadCreator, but not metaCreator
//
// Returns:
// {
// type: 'TYPE',
// error: true,
// payload: new TypeError('foo'),
// meta: 'bar'
// }
const actionCreator = createAction(TYPE, (a) => a, (b) => b)
actionCreatorA(errorObj, 'bar') Maybe I am missing sth, but clarification for this would be very helpful. This is not only a question for @yangmillstheory, everyone can give his opinion to this. |
Ping @jrasky, @TylerBrock, @noahsilas, @vbud, @arb. |
Hmm, your list confuses me a little bit. This PR is such that Regardless, if the convention is to use |
@jrasky the changes in this PR are already sufficient in your opinion to fullfill your needs?? |
I was thinking about saying this, but looks like it's already been said. We should disambiguate between |
// 4. Accept a second parameter as function for adding meta to the object
//
// Returns:
// {
// type: 'TYPE',
// payload: 'foo',
// meta: 'bar'
// }
const actionCreator = createAction(TYPE, (a) => a, (b) => b)
actionCreator('foo', 'bar') I think this behavior is incorrect; Otherwise, the examples look 👌 . To add to the first example, I don't like that we're coercing a non-function here. Like elsewhere in the API, we should not silently coerce, but ask for a function or See also #97 (comment). However, this hardening doesn't belong in this PR; I can open up a separate one for it if you're on board.
I don't see anything in the list about omitting payload when |
@@ -95,7 +95,8 @@ describe('createAction()', () => { | |||
|
|||
const explictNullAction = createAction(type)(null); | |||
expect(explictNullAction).to.deep.equal({ | |||
type | |||
type, | |||
payload: null | |||
}); | |||
|
|||
const baz = '1'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we get rid of this test? It doesn't have anything to do with the test name and is already being tested here.
Regarding #128 (comment), I don't see any tests where we're calling action creators with I do see calls to See #128 (comment). |
@timche Let's update the README to specify that the After that, LGTM. |
@yangmillstheory what about number five? I'm probably confused about how this relates to the other examples. Otherwise, something in the README would be perfect. |
Thanks for clarifying, I completely missed that; the fifth example is what you're referring to. I think that example is specifying the wrong behavior; we shouldn't omit payload if given an This would require no new code changes, since we've always delegated to // Returns:
// {
// type: 'TYPE',
// payload: 'bar',
// meta: 'bar'
// }
const actionCreator = createAction(TYPE, undefined, (a) => a)
actionCreator('bar') but is redundant with the second example, which is correct. We should probably all be aligned on this point... |
Thanks for the discussion guys. I've fixed example 4 according to your comment @yangmillstheory: const TYPE = 'TYPE';
const errorObj = new TypeError('foo')
// 1. Throw an error when payloadCreator is not `undefined` or a function
//
// Returns:
// new TypeError('payloadCreator must be undefined or a function')
const actionCreatorB = createAction(TYPE, 'foo')
// 2. Use identity function when payloadCreator is `undefined`
//
// Returns:
// {
// type: 'TYPE'
// payload: 'foo'
// }
const actionCreator = createAction(TYPE)
actionCreator('foo')
// 3. Use payloadCreator when it is a function
//
// Returns:
// {
// type: 'TYPE',
// payload: {
// a: 'foo',
// b: 'bar'
// }
// }
const actionCreator = createAction(TYPE, (a, b) => ({ a, b }))
actionCreator('foo', 'bar')
// 4. Accept a second parameter as function for adding meta to the object
//
// Returns:
// {
// type: 'TYPE',
// payload: 'foo',
// meta: 'bar'
// }
const actionCreator = createAction(TYPE, (a) => a, (a, b) => b)
actionCreator('foo', 'bar')
// 5. Omit payload when payloadCreator is `undefined`, but a second parameter has been set for adding meta to the object
//
// Returns:
// {
// type: 'TYPE',
// meta: 'bar'
// }
const actionCreator = createAction(TYPE, undefined, (a) => a)
actionCreator('bar')
// 6. Set `error` to `true` when payload is an Error object and bypass any payloadCreator
//
// Returns:
// {
// type: 'TYPE',
// error: true,
// payload: new TypeError('foo')
// }
const actionCreatorA = createAction(TYPE)
const actionCreatorB = createAction(TYPE, (a, b) => ({ a, b }))
actionCreatorA(errorObj)
actionCreatorB(errorObj)
// 7. Set error to true when payload is an Error object and bypass any payloadCreator, but not metaCreator
//
// Returns:
// {
// type: 'TYPE',
// error: true,
// payload: new TypeError('foo'),
// meta: 'bar'
// }
const actionCreator = createAction(TYPE, (a) => a, (b) => b)
actionCreatorA(errorObj, 'bar') Regarding example 5: It's not very clear to me then when to use Also a more understandable example for 5 with // Returns:
// {
// type: 'TYPE',
// payload: 'bar',
// meta: 'bar'
// }
const actionCreator = createAction(TYPE, null, (a, b) => b)
actionCreator('bar') Before I change the readme, code and tests, the overall outcome:
Is that correct or am I missing sth? |
1 sounds correct. For 2, why do we need to allow Also, will we throw errors in the case that we receive a payload creator that is not |
I would agree that using |
Yes, please. Alright, so lets agree on the following for 2:
Example: // 5. Omit payload when payloadCreator is `undefined`, but a second parameter has been set for adding meta to the object
//
// Returns:
// {
// type: 'TYPE',
// payload: 'foo',
// meta: 'bar'
// }
const actionCreator = createAction(TYPE, undefined, (a, b) => b)
actionCreator('foo', 'bar') Overall result now is:
If we agree on these changes for |
I'm OK with the proposed. ☝ |
Seems weird to use Isn't it convention to use Where Also, there is the fact that undefined can be overwritten, causing this rule to exist http://eslint.org/docs/rules/no-undefined. I've used this on all my projects for years now. |
@BerkeleyTrue take a look at the previous discussion on #115. The short of it is that treating It's no longer the case that you can change the value of |
@jrasky I see. Thanks for the clarification. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@timche is anything blocking this merge? |
@yangmillstheory Please review once more, I've removed an obsolete test. |
expect(explictNullAction).to.deep.equal({ | ||
type | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was this failing before?
Also, I'm wondering if there's a test somewhere that says the following:
const explictNullAction = createAction(type)(null);
expect(explictNullAction).to.deep.equal({
type,
payload: null,
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it was failing before, I fixed it before but I've removed it because of your comment 😅
I've been thinking more about Example 2, which eventually resulted in this. I've been questioning it, wondering if it'll lead to more annoyance than usefulness and clarity. However, I found some more material on the benefits of treating
So, I still think we're doing the right thing (there seems to be plenty of justification for it in the above material), even though I don't feel as strongly about it as before. |
Thanks for the research @yangmillstheory, feeling more confident now that we are doing this change 😁 |
Also went in this problem a minute ago. |
We are releasing |
|
Continuing #115 and part of #122 (v1.0.0).