Skip to content

Can't update defaultChecked/defaultValue. #4618

Closed

Description

@DylanPiercey

When I rerender a component with "defaultChecked" or "defaultValue" react fails to update the "value" and "checked" attribute accordingly.

Before you say "use a controlled input" I would argue that this is a bug as it basically disallows uncontrolled forms with "reset" buttons. (It will always reset to whatever the initial default value was).

Activity

  1. changed the title [-]Can't update default attributes.[/-] [+]Can't update defaultChecked/defaultValue.[/+] on Aug 12, 2015
  2. jimfb commented on Aug 12, 2015

    @jimfb
    Contributor

    You can specify a dynamic key on your uncontrolled input, and when you want to reset it, you can bump the key value (with the new defaultValue being empty string or being whatever "default/reset" value you want), which will effectively reset the component's internal state.

    You could also break out of React and use plain javascript to manually reset the input's state (since you're using an uncontrolled input anyway, the component is effectively expecting triggers outside of React to modify it, so this doesn't break the component's mental model/contract).

    Or you could just "use a controlled input" as you mentioned before, which is the correct solution IMHO.

    Anyway, there are several options at your disposal. Your job as an engineer is to choose the one that's best for your use case.

  3. DylanPiercey commented on Aug 13, 2015

    @DylanPiercey
    Author

    @jimfb I understand that there are some hacks to achieve the desired result (which I am using) although I would expect that the "defaultValue" in my virtual dom accurately reflects the "defaultValue" in the real dom. It just seems odd for react to completely disregard any modifications to defaultValue.

  4. jimfb commented on Aug 13, 2015

    @jimfb
    Contributor

    defaultValue is, in some sense, the hack (for people who want a "fire and forget" solution to implementing their input tags). Think of it as an "initialValue" instead of "defaultValue" and it may make more sense to you. The point is that you get a single opportunity to specify the value at component creation time, and then the component takes over from that point forward.

    React pushes you to top-down data flow for a reason. When you have siblings randomly influencing a node's state, it becomes very difficult to reason about the state of your application, and even harder to understand the ramifications of a given change.

    If you need to be able to influence a component's state, then that state is no longer internal to the component (by definition). Modeling it as internal state is a violation of the abstraction because touching a component's internal state is a violation of the abstraction. If you need to control the component's state, you should probably be using a controlled component, IMO.

  5. DylanPiercey commented on Aug 13, 2015

    @DylanPiercey
    Author

    @jimfb I understand your view, and what I want is a "fire and forget" form, which react seems to support.

    It just seems odd that if uncontrolled forms are supported at all that you don't allow the browser to handle defaultValue and defaultChecked. All I am trying to do is reset an uncontrolled form and it seems impossible in react without hacks or rewriting it into a controlled form (Which I do not necessarily have control over since some of my dependencies use uncontrolled inputs and will not work with the native forms reset).

    Even if my form was controlled because of this limitation it is unreliable to use the native "reset()" on any form because I cannot trust that react actually updated the default values for my form as my form is re-rendered.

    So are you saying that react users should never rely on "reset" for forms that may have had their "initialValues" changed?

  6. jimfb commented on Aug 13, 2015

    @jimfb
    Contributor

    @DylanPiercey I'm saying that resetting the form currently "resets" the form elements to their initial values, which is the currently expected behavior (conceptually, the component is saving the initial property into state on first mount, and using that state variable from that point forward; you can't go back in time, so you can't change that initial value, because it was already sent). If you want more control over the state of your input components, I would recommend using a controlled input, which exists for the exact purpose of giving you the control.

    You could always implement your own component which behaves like an uncontrolled input (does anything internally) and implements whatever semantics you'd like.

  7. sophiebits commented on Aug 13, 2015

    @sophiebits
    Contributor

    @DylanPiercey You can also grab the native DOM node and set .checked on it manually if you prefer. Honestly, I'm confused what API you're proposing though. How would React know when to reset the value and know when to keep it as what the user entered?

  8. DylanPiercey commented on Aug 13, 2015

    @DylanPiercey
    Author

    @spicyj My current solution is to create my own inputs and do this:

    Input = React.createClass({
      componentWillReceiveProps(nextProps) {
            if (
                nextProps.defaultValue !== this.props.defaultValue ||
                nextProps.defaultChecked !== this.props.defaultChecked
            ) {
              var input = React.findDOMNode(this);
              input.defaultValue = nextProps.defaultValue;
              input.defaultChecked = nextProps.defaultChecked;
            }
      },
    
      render() { return <input {...this.props}/> }
    })

    Basically it just keeps the defaultValue and defaultChecked in sync with the dom. Which only actually updates the input if it has never been touched by the user, or the form has reset. I guess this is just a little misleading because that is what the browser does by default when you modify "defaultValue".

    I would propose something like this (as it seems like what we want and is unambiguous):

    <input initialValue={ 1 } defaultValue={ 2 }/>

    This could throw with both a defaultValue and initialValue, or initialValue could override defaultValue but only for the initial render.

  9. sophiebits commented on Aug 23, 2015

    @sophiebits
    Contributor

    Maybe we can make defaultValue update the DOM too. Few people use reset buttons so this hasn't come up.

  10. DylanPiercey commented on Sep 7, 2015

    @DylanPiercey
    Author

    @spicyj any further thoughts on this?

  11. sophiebits commented on Nov 10, 2015

    @sophiebits
    Contributor

    I'm happy to take a pull request that passes defaultValue through to the DOM. It looks like that is linked directly to the value attribute. Probably the best way to do this is to change our code so that value is treated as an attribute (using .setAttribute('value', x) instead of .value = x) in the property config which is equivalent to setting .defaultValue, then ReactDOMInput can manually set .value instead of going through DOMPropertyOperations. Open to other suggestions.

    image

  12. CodeOfDavid commented on Nov 26, 2015

    @CodeOfDavid

    @DylanPiercey I could not agree with you more

  13. leandro commented on Dec 4, 2015

    @leandro

    👍 I definitely endorse this, as I'm also facing the same issue.

    I simply want the ability to keep using my input as an uncontrolled input but with the ability to change the defaultValue/defaultChecked and reflect that change in the active DOM element.

  14. 15 remaining items

  15. added a commit that references this issue on Aug 31, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions