Omit payload on undefined only#128
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 |
| payload: null | ||
| }); | ||
|
|
||
| const baz = '1'; |
There was a problem hiding this comment.
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. |
|
@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.
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.
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).