-
Notifications
You must be signed in to change notification settings - Fork 47k
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
Set value by setAttribute(value) for html input box for #4618 #5680
Conversation
var node = ReactDOMComponentTree.getNodeFromInstance(inst) | ||
|
||
// To avoid side effects (such as losing text selection), only set value if changed | ||
if (value != node.value) { |
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.
Previously, the string cast happened before this comparison, so value
of 3
and node.value
of '3'
would not trigger a set. We should keep that.
It shouldn't be hard to make this work for textarea too, right? I guess select may be a bit harder. Btw – lint is failing. |
acff76c
to
75ca295
Compare
Fixed linting issues. |
@hayesgm updated the pull request. |
Also, @spicyj, this removes all need for |
I would like to have consistency between input and textarea here. I guess for textarea we need to change the children/textContent? :\ I do think this is better than #5666 even though it seems like more work. Yeah, want to do a follow-up PR to remove HAS_SIDE_EFFECTS? |
75ca295
to
c974cb5
Compare
@hayesgm updated the pull request. |
Got this working with This playground is up-to-date with this change: https://jsbin.com/tobuye/edit?html,js,output @spicyj Happy to create that PR once this one is done. |
Any update on this PR? Happy to make any changes required to get this pulled. |
@spicyj I think I've said it before, but using attributes instead of properties for |
HTML does not have a concept of switching from |
@jimfb Do you want to take a look at this one? |
var container = document.createElement('div'); | ||
|
||
var el = ReactDOM.render(<input type="text" value="0" readOnly="true" />, container); | ||
var node = ReactDOM.findDOMNode(el); |
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.
ReactDOM.render returns the DOM node; you don't need to call findDOMNode
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.
Went ahead and replaced all of these after a direct call to ReactDOM.render()
in ReactDOMInput-test.js and ReactDOMTextarea-test.js
@spicyj I don't agree, put an input on a page, type into it and inspect. That's the convention set by the standard/browsers, we will be explicitly going against that and controlled inputs will thus differ from uncontrolled inputs in behavior too. Any change to a controlled input that doesn't emit an event (like autofill) will also cause unexpected behavior as the attribute will then not mirror the property until updated. What is the argument for using attributes? |
|
||
expect(node.value).toBe('1'); | ||
|
||
ReactDOM.render(<input type="text" value={3} defaultValue="2" />, container); |
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 feel like controlled inputs should not take in a defaultValue
- that should be illegal. In a controlled world, a button type=reset
should have no effect. To reset a controlled component, the click handler of the reset button should update application state. It makes no sense to have both value
and defaultValue
specified.
Filed #5819
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.
Removed this test case to defer to changes in #5819
I'm inclined to agree with @spicyj on this one:
I'm fine with using attributes here, to match the behavior of a fresh render. I left a few comments/nitpicks. Conceptually, this diff looks fine to me ( 👍 ) . |
@syranide Nowhere have we said that updating the value via React should have the same behavior as typing into an input, and I'm not sure why that should be the case either. It is cleaner and simpler conceptually to have it match what you would get on a clean rerender as long as that doesn't cause problems practically. The motivation for this change is #4618 – React currently fails to update the defaultValue property (which always matches the value attribute) which means it is not possible to change an input's "default value" after initial render, which is used by an |
OK, that argument I kind of get, but if you're using controlled inputs, I would think the solution is to reset the state, that's the point of controlled inputs. Anyway, that's HTML for you, I get it. But if that's what we want then why not just set the PS. I also get the desire to have controlled inputs behave as if they're always fresh... but it's odd behavior for HTML. But that's my opinion. |
@syranide |
@syranide My screenshot shows exactly that. |
@hayesgm updated the pull request. |
This is now rebased to master. It also properly addresses the (mostly minor) issues raised by @jimfb's review. |
stub = ReactDOM.render(<textarea>gorilla</textarea>, container); | ||
expect(node.value).toEqual('giraffe'); | ||
expect(node.value).toEqual('gorilla'); |
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.
Hmm this is a behavior change i hadn't anticipated. I was thinking that this PR would be unobservable if you don't have a reset button (or CSS selectors based on the value attribute, etc) but not if this is the behavior. We'll have to think on this probably. Even if this is desirable overall it could break people who expect the other behavior so we need to be cautious.
cc @zpao – what do you think? In order to make <input type="reset" />
work reasonably, this PR changes the value attribute whenever defaultValue
is set (equivalent to the .defaultValue
property), but if there hasn't been any user interaction then doing so also changes the actual value.
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.
Don’t we want to remove support for <textarea>{children}</textarea>
anyway? Might as well do that together with this. (Obv in 16 earliest.)
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.
We do (and we've had that warning for a while now so removing it should be easy), but this has the same problem with <textarea defaultValue="gorilla" />
I think.
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.
Oh, I see. Even if people migrated to defaultValue
they’d still rely on the old behavior?
I think the only other thing I'm worried about is if this can cause extra cursor jumps when defaultValue is set. Code comments indicate it might be a problem in IE9. |
@spicyj I'd be happy to test this in an IE9 VM. I'll report back. As per changing defaultValue changes value (unless it's been affected by the user), I thought that was actually part of the spec that we wanted to change. To me, it was always odd behavior that "defaultValue" was a one-and-done. It makes logical sense that updating defaultValue updates the input, so long as it was never user manipulated. I agree, however, this goes against the current documentation and should be considered a breaking change (albeit minor). |
For my first look at IE9, it doesn't look like there's any issue with stealing focus / cursor. Internet Explorer (11 included) looks to not set the value of a
As evidenced in this example, Chrome/FF/Safari all display the "defaultValue" in lieu of an unset value in both and <textarea> elements. Internet Explorer (9/10/11) will display the defaultValue on elements, but leaves <textarea> blank. In any case, all browsers reset the elements to the correct value after a reset. |
Not really. We shouldn't do this switch if it introduces behavior differences between browsers. I'm not even sure this is desirable and would feel more comfortable if the effective value did not change when changing defaultValue. I think that might be possible if we save the old value before each update and restore it after. |
I agree here that there's an issue on cross-browser behavior with Internet Explorer for this PR. At this point, can we clarify what behavior we want and which approach (if any) we believe can achieve that. This conversation might be better placed in the original issue thread than this PR. |
I’m going to close this out because it doesn’t merge cleanly anymore and, more importantly, there is no consensus on how to proceed. Both this PR and #5666 can exist as a reference for both approaches but let’s continue the discussion in #4618 to figure out what behavior we actually want, now that we know drawbacks of either implementation. Thank you for your work on this! |
it('should take updates to `defaultValue` for uncontrolled textarea', function() { | ||
var container = document.createElement('div'); | ||
|
||
var node = ReactDOM.render(<textarea type="text" defaultValue="0" />, container); |
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.
Note for if we come back to this: no need for type="text"
on textareas.
Nevertheless, unless I’m mistaken, it introduces a breaking change in how More info on behavior change: #5680 (comment). |
@@ -169,7 +169,7 @@ var HTMLDOMPropertyConfig = { | |||
// Setting .type throws on non-<input> tags | |||
type: MUST_USE_ATTRIBUTE, | |||
useMap: null, | |||
value: MUST_USE_PROPERTY | HAS_SIDE_EFFECTS, | |||
value: MUST_USE_ATTRIBUTE, |
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.
If HAS_SIDE_EFFECTS
is now unused then the corresponding logic should be removed from DOMPropertyOperations
as well? (PS. Also, this is outdated and needs to be rebased)
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.
Already mentioned here: #5680 (comment), resolution was that HAS_SIDE_EFFECTS can be handled as a followup PR.
This is an alternate approach for #5666, using
setAttribute(value)
instead ofdefaultValue
as a DOM property. Both this and #5666 are fixes for #4618 and are mutually exclusive approaches.Fixes issue #4618, which allows updates to defaultValue on uncontrolled s by changing
element.value
viaelement.setAttribute(value)
. We movehasSideEffects
code into the input and textarea wrappers (each wrapper updates still viaelement.value = ...
). Browsers will reflect changes tosetValue(value)
on<input>
elements unless the user has adjusted the value on an uncontrolled element. This is the approach suggested by @spicyj.Note: even after this patch, changes to defaultValue on textarea and select elements will not be reflected after the component is mounted.
Here's a simple test of the patch on JSBin: https://jsbin.com/tobuye/10/edit?html,js,output