React: Controlled inputs with the potential for `undefined` value

Created on 9 Mar 2016  Â·  12Comments  Â·  Source: facebook/react

Upgraded to React 15rc1 today, and a new warning appears to have cropped up:

Warning: SearchBox is changing a uncontrolled input of type text to be controlled. Input elements should not switch from uncontrolled to controlled (or viceversa). Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://fb.me/react-controlled-components

The component it's referring to is indeed a controlled component for the duration of its lifetime:

<input
  type="text"
  className="typeahead"
  onKeyUp={::this.controlsHandler}
  onChange={::this.changeHandler}
  value={this.props.search.get('term')}
  ref={(i) => this._input = i}
/>

The problem, I've realized, is that on first render, this.props.search.get('term') returns undefined, because its value is only populated with text put into the input.

I expect this is a pretty common pattern for controlled components?

Otherwise loving the release - having all SVG attributes at my disposal is very exciting :)

Most helpful comment

How about removing this warning? It really annoying and makes me write unnecessary checks.
To my mind it is normal when in flux Store you have some data which is undefined

All 12 comments

Ultimately, what you are really trying to specify is "this component is controlled, but is currently empty". It is intentional that you specify this by setting the value to be the empty string. When the value is specified as undefined, React has no way of knowing if you intended to render a component with an empty value or if you intended for the component to be uncontrolled. It is a source of bugs. This is why the warning exists.

It sounds to me that this.props.search.get('term') should return the empty string instead of undefined, assuming the initial value of the search box is the empty string.

Alternatively, you could do a null/undefined check in this component, before passing the value to the input.

We haven't received too much push back on this one, so I think it's uncommon enough that the benefit outweighs the cost. Therefore, we probably aren't going to change this, so there is nothing actionable in this bug. However, if our thinking changes on this matter, we can certainly reconsider.

Fair enough! Makes perfect sense :)

How about removing this warning? It really annoying and makes me write unnecessary checks.
To my mind it is normal when in flux Store you have some data which is undefined

A bit silly to get this warning. I'm not actually changing an uncontrolled input to a controlled input just because the default value is undefined. The element is controlled from the start. So the warning is wrong. So do I ignore the warning or do I implement a workaround for just this invalid warning by specifying || ''? I'd prefer the first, but sadly then my console gets way too messy. Is it possible to disable warnings?

+1, please it's really annoying.

+1

React has no way of knowing if you intended to render a component with an empty value or if you intended for the component to be uncontrolled. It is a source of bugs.

While i can see the point, that this might be a source of bugs. I kind of disagree on the first part.
The value property is part of the props object. Therefor you can use Object.keys() to figure out if that key has been intentionally added to the props object or if it hasn't been. The key will exist if you explicitely set the property even if its value is undefined.
When going with this approach <MyInput value={ undefined } /> would be a controlled component and <MyInput /> would be uncontrolled.

I found the same problem my code is like so:
type="checkbox" className="mdl-checkbox__input"
checked={self.state.filterValues[col] &&
self.state.filterValues[col][termString(bindings.resource)]}
onChange={self.onFilterChange.bind(null, {binding: col, value: bindings.resource})}
/>

Warning: ResourceList is changing an uncontrolled input of type checkbox to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://fb.me/react-controlled-components

@MartijnHols careful using || operator as a work-around: if the state variable is set to 0 or false, then comparison this will evaluate to '' (empty string) and overwrite the field value. My work-around was to use a helper function, https://github.com/garudacrafts/fun-fp/tree/master/src/function/coalesce, to check for undefined using typeof operator and wrap all my variables, like so: value={coalesce(this.state.session.date, '')}.

It confused me badly at first :) Especially because that warning would pop up when you change the field, not when the value (undefined) was set during first render.

This warning is absolute idiocy.

@jimfb
One thing I don't understand about the underlying idea is this: Uncontrolled components are supposed to use fValue instead of value – why does that not lead to the reasoning that the use of defaultValue means that the component is uncontrolled?

If both defaultValue and value are undefined, the component would assume to be controlled, which should not really break anything, right? So that approach should cover both use cases and enable undefined as a valid value for value without the warning.

Also, I find @cdxOo's argument quite compelling.

Was this page helpful?
0 / 5 - 0 ratings