Skip to content

Conversation

gasi
Copy link
Contributor

@gasi gasi commented Jun 10, 2014

Notes

  • Tests pass.
  • Lint reports many warnings but not due to newly added code.
  • Previously signed CLA.

@chenglou
Copy link
Contributor

@sebmarkbage

CHANGELOG.md Outdated
Copy link
Collaborator

Choose a reason for hiding this comment

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

No need to update the changelog here; we'll do it when we do a release (and organize it in a way that hopefully makes more sense than the individual commit bullets points).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍 Removed CHANGELOG entry.

@gasi
Copy link
Contributor Author

gasi commented Jun 10, 2014

Removed CHANGELOG entry and the minimal changes are now ready for review.

@sebmarkbage
Copy link
Collaborator

If you start passing undefined values in to a renderable slot you can no longer have default values for that same slot. This is a potential refactoring hazard.

It's also easy to accidentally return undefined by missing a return case in a function.

function render() {
  if (x) return <Foo />;
  if (y) return <Bar />;
  // undefined
}

Failing this type check helps prevent such errors.

I can see that it's a pain to check for the existence of a value. :(

<Foo component={this.props.component || null} />

This does forces you to make the choice if you want to use the default prop or explicitly null.

You can always make a renderable prop optional which is suppose to be the same as undefined.

@mathieumg
Copy link
Contributor

What about: {optionalBoolean && <MyComponent />}?

If optionalBoolean is undefined this will return undefined. Is the "solution" here to do this {optionalBoolean ? <MyComponent /> : null}?

@sophiebits
Copy link
Collaborator

@sebmarkbage We should at least make [<a />, <b />, undefined] pass the renderable check, no?

@gasi
Copy link
Contributor Author

gasi commented Jun 11, 2014

Yes, I agree with @spicyj to allow [<a />, <b />, undefined] and I believe my changes enable exactly that. The case you describe is still covered and a simple undefined (outside of […] array) will still throw an error:

it('should warn for missing required values', function() {
typeCheckFail(
PropTypes.renderable.isRequired,
null,
'Required prop `testProp` was not specified in `testComponent`.'
);
typeCheckFail(
PropTypes.renderable.isRequired,
undefined,
'Required prop `testProp` was not specified in `testComponent`.'
);
});

@sebmarkbage
Copy link
Collaborator

Ideally it would be the same behavior for top-level and nested.

You can implement default props as ES6 destructuring which could introduce similar issues at the array level.

There's also a problem if you don't have defaults and don't have explicit prop types in intermediate components. This could warn you about undefined values even without explicit propTypes:

<Wrapper>{this.props.left}{this.props.right}</Wrapper>

It's disturbing that it's relaxing the type check when it's nested.

Reopening for proper discussion.

@mathieumg An optional boolean can have an explicit default prop. Makes it a little bit easier to reason about the actual value if it's only true/false.

@sebmarkbage sebmarkbage reopened this Jun 11, 2014
@sophiebits
Copy link
Collaborator

@sebmarkbage Isn't this a reasonable piece of code to write in render?

var left;
if (showLeft) {
  left = <Left />;
}

return (
  <div>
    {left}
    <Right />
  </div>
);

I guess that's not 100% the same as what we're talking about here, but it's close.

@sebmarkbage
Copy link
Collaborator

@spicyj Not really, no. It looks like an accidental missing else statement. I'd probably lint against that. var left = null; on the top line would be reasonable.

But even then, that's a mutable structure. I'd probably prefer the const form.

@gasi
Copy link
Contributor Author

gasi commented Jun 11, 2014

Thanks for reopening for discussion, @sebmarkbage. I definitely want to find a solution that allows for more use cases of renderable without harming existing checks.

You can implement default props as ES6 destructuring which could introduce similar issues at the array level.

Can you give an example?

It's disturbing that it's relaxing the type check when it's nested.

If you believe that, shouldn’t [null] fail the type check as well then?

In the original example I gave in #1647, what style would you recommend to address that undefined in an array is not a valid renderable?

@gasi
Copy link
Contributor Author

gasi commented Aug 14, 2014

Any update on this?

@sebmarkbage
Copy link
Collaborator

I think the most convincing use case for me is the case where you have an optional property.

<Foo child={this.props.childOrUndefined} />

This might be reason enough to allow this.

However the main issue is that this resolves differently for undefined and null:

var { childOrUndefined = <Foo /> } = this.props;

Therefore passing undefined may actually change behavior of underlying classes in confusing ways. Seems like a little bit of boilerplate to ensure which one you mean seems like a decent way to resolve this issue and ensure that refactoring doesn't cause unforeseen bugs.

@sebmarkbage
Copy link
Collaborator

Closing this out again because I think that making it optional is enough. Will follow the lead from Flow here and align with Flow once it settles. I still think undefined needs to be treated differently from null here.

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.

5 participants