Skip to content
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

Closed
wants to merge 1 commit into from

Conversation

taylorhakes
Copy link
Contributor

Updated composeStores to throw if undefined is returned. #191

@taylorhakes taylorhakes force-pushed the compose-store-undef branch 3 times, most recently from 5e2d6d7 to b2476c5 Compare June 30, 2015 03:01

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) {
Copy link
Contributor

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?

@gaearon
Copy link
Contributor

gaearon commented Jun 30, 2015

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.

@gaearon
Copy link
Contributor

gaearon commented Jun 30, 2015

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.

@taylorhakes
Copy link
Contributor Author

I changed it because I was considering unexpected issues in production. For instance, if the default doesn't return undefined, but one of their case statements. This could cause their whole state not to update. It is debatable whether an undefined state is worse than causing a full update not to work.

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.

@taylorhakes
Copy link
Contributor Author

I made that change to your suggestion. I could be wrong and people will prefer a hard error, even in production.

@taylorhakes taylorhakes force-pushed the compose-store-undef branch 3 times, most recently from 2faad15 to 10f7c59 Compare June 30, 2015 11:46
stack: (state = []) => state,
bad: (state = 1, action) => {
if (action.type === 'something') {
return undefined;
Copy link
Contributor

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.

Copy link
Contributor Author

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?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just return is enough :-).

@taylorhakes taylorhakes force-pushed the compose-store-undef branch from 10f7c59 to 5965423 Compare June 30, 2015 12:22
@gaearon
Copy link
Contributor

gaearon commented Jun 30, 2015

If something warns in development it must no-op in production.
If something throws in development it must throw 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;
Copy link
Contributor

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?

Copy link
Contributor Author

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?

Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor

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;
  }
}

Copy link
Contributor Author

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

@gaearon
Copy link
Contributor

gaearon commented Jun 30, 2015

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 :-)

@taylorhakes
Copy link
Contributor Author

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.

This was referenced Jun 30, 2015
@gaearon
Copy link
Contributor

gaearon commented Jun 30, 2015

@taylorhakes Once you get to that, would you please make another PR on top of #195? It contains the renaming of this function..

@taylorhakes
Copy link
Contributor Author

I will need to close this pull request to make a pull request against the alpha branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants