-
-
Notifications
You must be signed in to change notification settings - Fork 15.3k
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
Throw error on undefined value from store function #193
Conversation
5e2d6d7
to
b2476c5
Compare
|
||
export default function composeStores(stores) { | ||
const finalStores = pick(stores, (val) => typeof val === 'function'); | ||
|
||
if (process.env.NODE_ENV !== 'production') { | ||
Object.keys(finalStores).forEach(function(key) { |
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.
Why didn't you use an arrow function here?
This is "probing" a reducer but I actually want the check to run every time a reducer is called. So it needs to be inside the function actually calling it. |
Also, because it is a hard constraint, it should be enforced in production too. No need for the if statement. Otherwise pros and dev bugs would differ. |
f3261b7
to
0405d79
Compare
I changed it because I was considering unexpected issues in production. For instance, if the default doesn't return I think it generally shouldn't be an issue in dev. I think that someone might run into the error at the wrong time in production, unfortunately. |
I made that change to your suggestion. I could be wrong and people will prefer a hard error, even in production. |
2faad15
to
10f7c59
Compare
stack: (state = []) => state, | ||
bad: (state = 1, action) => { | ||
if (action.type === 'something') { | ||
return undefined; |
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.
I'm not very fond of undefined
since it may be overridden.
var undefined = null
console.log(undefined) // null
void 0
is less readable but works as expected.
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.
I thought about doing that, but I wasn't sure the stance of this repo. I would also need to change it in composeStores.js. What are people's thoughts?
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.
Just return
is enough :-).
10f7c59
to
5965423
Compare
If something warns in development it must no-op in production. You're not going to "save" the app by returning undefined in production. It's already unexpected what will happen (because it never happened in dev apparently). It's important to keep crashes consistent. Otherwise you won't be able to reproduce a production crash report in development. The different stack trace will mislead you and you'll have a hard time figuring out why you never have crashes with that stack trace in development. |
import pick from './pick'; | ||
|
||
// UNDEF = undefined; | ||
const UNDEF = void 0; |
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.
It looks like a hack. Can you please check typeof instead?
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.
This is a pretty common pattern. I will make the change. How should I fix the other UNDEF use in the test?
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.
You can replace return UNDEF
with just return
, and use typeof x === 'undefined'
as a check.
Or are you referring to something else?
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.
Unfortunately, there is an ESLint rule that forbids return;
when there is another type returned elsewhere. I think we can just use undefined
though. We don't have to worry about users overwriting undefined
in tests.
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.
I think you can also invert the condition.
Instead of returning undefined in some cases, return something in other cases.
function bad() {
if (action.type !== 'something') {
return something;
}
}
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.
I thought about that. I was trying to make the test as obvious as possible. I will change it to above
Here's a potential crazy issue you might encounter if undefined was tolerated in production: loss of user data. Instead of crashing, data is overridden, and the app saves the bad state. Crashing isn't always bad :-) |
Definitely, I hinted above that there is a trade off. If the app crashes in prod, losing state might be better than blocking the action. Depends on the app. I just trying to note that by fixing one issue, we are introducing another. Probably will be less an issue than the original. Time will tell. I am fine making it a hard error. I understand your reasoning. |
@taylorhakes Once you get to that, would you please make another PR on top of #195? It contains the renaming of this function.. |
I will need to close this pull request to make a pull request against the alpha branch. |
Updated composeStores to throw if undefined is returned. #191