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

Warn when "false" or "true" is the value of a boolean DOM prop #13372

Merged
merged 4 commits into from
Aug 14, 2018
Merged

Warn when "false" or "true" is the value of a boolean DOM prop #13372

merged 4 commits into from
Aug 14, 2018

Conversation

motiz88
Copy link
Contributor

@motiz88 motiz88 commented Aug 12, 2018

Hi! 😄

This is my first contribution that actually changes runtime behaviour, and involved some guesswork as to where to make what change to get the desired effect - so do take it with a grain of salt. I'm super willing to learn more about how React is written and fix anything that needs to be fixed in this PR, if the functionality is welcome.


This PR adds a new DEV-mode warning when the value "false" (case-insensitive) is found in a DOM prop of type BOOLEAN, recommending the use of the boolean value false instead.

While working on facebook/flow#6727 I came across the different types of boolean DOM props, and specifically the fact that BOOLEAN props (e.g. hidden) treat the string "false" as equivalent to boolean true, whereas BOOLEANISH_STRING props (e.g. spellCheck) treat it as equivalent to boolean false - an inconsistency that follows from the HTML spec, but one that can conceivably trip up developers, hence a warning.

I'm not entirely sure what OVERLOADED_BOOLEAN props should do about "false" - currently the warning doesn't apply to them.

EDIT: Per feedback below, this now also warns on "true", and only warns on case-sensitive (lowercase) matches.

@pull-bot
Copy link

pull-bot commented Aug 12, 2018

Details of bundled changes.

Comparing: 725e499...f70a0eb

react-dom

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-dom.development.js +0.1% +0.1% 641.27 KB 641.81 KB 150.69 KB 150.86 KB UMD_DEV
react-dom.development.js +0.1% +0.1% 637.41 KB 637.95 KB 149.53 KB 149.69 KB NODE_DEV
react-dom-server.browser.development.js +0.5% +0.7% 103.08 KB 103.62 KB 27.49 KB 27.67 KB UMD_DEV
react-dom-server.browser.development.js +0.5% +0.6% 99.21 KB 99.75 KB 26.54 KB 26.7 KB NODE_DEV
react-dom-server.node.development.js +0.5% +0.6% 101.13 KB 101.67 KB 27.07 KB 27.23 KB NODE_DEV
ReactDOM-dev.js +0.1% +0.1% 644.54 KB 645.21 KB 147.76 KB 147.93 KB FB_WWW_DEV
ReactDOMServer-dev.js +0.7% +0.6% 100.31 KB 100.98 KB 26.25 KB 26.42 KB FB_WWW_DEV

Generated by 🚫 dangerJS

it('warns on the ambiguous string value "False"', function() {
let el;
expect(() => {
el = ReactTestUtils.renderIntoDocument(<div hidden="False" />);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since title case False doesn’t have special meaning I don’t think it’s worth testing for.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Happy to take your steer on this, I'd just like to state my case first for completeness: The thing I was trying to make safer was people drawing inferences from one "boolean" HTML attribute to another. Since enumerated attribute values are case-insensitive, spellCheck="False" does behave differently to hidden="False", in exactly the same way as the respective lowercase variants do. I take your point that most people would be using lowercase to begin with, so this is probably a rarer case, but it does theoretically occur.

To clarify, you're referring to dropping the toLowerCase() in the actual check, as well as removing this test, right?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah. I see your point but I think it's unlikely enough to be written accidentally and we want to make the checks as cheap as possible. Strict comparison is better than extra toLowerCase call.

propertyInfo.type === BOOLEAN &&
typeof value === 'string' &&
value.toLowerCase() === 'false'
) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let’s make value === 'false' the first condition. Since it’s rare we won’t have to check most other conditions.

@gaearon
Copy link
Collaborator

gaearon commented Aug 12, 2018

I think this makes sense overall. Maybe with warning for "true" too? You might be getting it from an API and only have actual "false" in production. But this would tell you early.

@@ -444,7 +444,7 @@ describe('ReactDOMInput', () => {

it('should take `defaultValue` when changing to uncontrolled input', () => {
const node = ReactDOM.render(
<input type="text" value="0" readOnly="true" />,
<input type="text" value="0" readOnly={true} />,
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 test was broken by adding the warning on "true". I opted to just fix what the warning was complaining about, which doesn't change the semantics of this test AFAICT.

@motiz88 motiz88 changed the title Warn when the string "false" is the value of a boolean DOM prop Warn when "false" or "true" is the value of a boolean DOM prop Aug 12, 2018
@motiz88
Copy link
Contributor Author

motiz88 commented Aug 12, 2018

@gaearon Thanks for the review! All feedback addressed.

expect(() => {
el = ReactTestUtils.renderIntoDocument(<div hidden="true" />);
}).toWarnDev(
'Received the string `true` for the boolean attribute `hidden`. ' +
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe add Although this works, it will not work as expected if you pass the string "false". to the true case.

@motiz88
Copy link
Contributor Author

motiz88 commented Aug 14, 2018

@gaearon Friendly ping 😄 I've amended the warning messages as per your feedback. Anything else you'd like to see here?

@gaearon gaearon merged commit 2c59076 into facebook:master Aug 14, 2018
@gaearon
Copy link
Collaborator

gaearon commented Aug 14, 2018

Looks great. Thank you.

@AlexGalays
Copy link

This is dead code when using a type system. Could this be enabled only in dev mode perhaps?

@AlexGalays
Copy link

Nevermind, didn't see the if (__DEV) :)

@veekas
Copy link

veekas commented Oct 20, 2018

Thanks for this PR, @motiz88. It surfaced a 1+ year-old bug in a codebase I work on. 👍

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

Successfully merging this pull request may close these issues.

6 participants