React: Unable to type in input after adding value prop

Created on 22 Oct 2016  路  12Comments  路  Source: facebook/react

I've made an an input field which makes an api call based on whats typed into it and then returns the results in a list. On clicking a list element the value in the text input field must get updated. When i add a value prop to the input i am unable to type anything into it. On removing the value prop from the input i am able to type but the set state does not work.

import { searchDoctorByName } from './../helpers/Api';
import React, { Component } from 'react';

class AutoCompleteSearch extends Component {
    constructor(props) {
        super(props);
        this.state = {
          value: '',
          suggestions: []
        }
    }

    autoSearchInputChange(e) {
      let searchValue = e.target.value;
      console.log(searchValue);
      if (!searchValue.trim()) {
        this.setState({ suggestions: [] })
        return ;
      }

      if (searchValue.length >= 3) {
          setTimeout(() => {
          searchDoctorByName(searchValue)
          .then((response) => {
            this.setState({ value : searchValue, suggestions: response.data })
          })}, 1000);
      }
    }

    selectItemFromList(doctorObject) {
      this.setState({
        value: doctorObject.name ,
        suggestions: [doctorObject]
      });
      console.log(this);
    }

    render() {
      console.log(this)
      let renderItems = () => {
        let listItems = this.state.suggestions.map((suggestion, index) => {
          let doctorObject = suggestion;
            return (
              <li onClick={() => this.selectItemFromList(doctorObject)} key={index}>
              {doctorObject.name}
              </li>
              );
          });
        return (
          <div>
            <ul className="doctor-list">
            {listItems}
            </ul>
          </div>
        );

      }
      console.log(this.state.value)
      return (
          <div className="form-group">
          <label className="control-label form-label col-md-4" htmlFor="auto-complete-search">Doctor Name</label>
          <div className="col-md-20">
            <input className="custom-input"type="text" value={this.state.value} id="auto-complete-search" required
              placeholder="Enter Doctor name"
              onChange={(e) => this.autoSearchInputChange(e)}
              />
              {this.state.value}
              {this.state.suggestions.length > 0 ? renderItems() : null}

          </div>
        </div>
      );
    }
}

export default AutoCompleteSearch;

using

this.autoSearchInputChange = this.autoSearchInputChange.bind(this) 

was also futile.

Most helpful comment

If you specify value the input becomes "controlled". This means you _must_ update the corresponding state in onChange. In React, value={something} literally means "value will always be something no matter what".

So you probably want to call

this.setState({
  value: e.target.value
});

inside your onChange handler.

Alternatively, you can remove the value prop altogether and make an input "uncontrolled". Then you won't have to call setState(), but you also won't be able to "control" its current value (e.g. transform or reset it).

You can learn more in Forms documentation section.

Does this help?

All 12 comments

If you specify value the input becomes "controlled". This means you _must_ update the corresponding state in onChange. In React, value={something} literally means "value will always be something no matter what".

So you probably want to call

this.setState({
  value: e.target.value
});

inside your onChange handler.

Alternatively, you can remove the value prop altogether and make an input "uncontrolled". Then you won't have to call setState(), but you also won't be able to "control" its current value (e.g. transform or reset it).

You can learn more in Forms documentation section.

Does this help?

Thanks. @gaearon Didn't know that state _had_ to be updated in the onchange.

As noted above, alternatively you can use uncontrolled inputs by not specifying the value at all. You can use defaultValue for an initial value in this case. But you won't be able to control the value then.

Umm just curious what purpose would an uncontrolled input serve.. I mean usually isnt the purpose of an input for taking some for of data..and then processing it in your application

You can read data from uncontrolled input just as fine in the onChange handler.

Use controlled inputs if you want to "control" them, e.g. to reset them, or to "force" them to have certain values e.g. when props change.

Use uncontrolled inputs if you don't care about "controlling" them and only need their current values.

I had a similar problem, and when I changed the code to change the state the input got replaced by a new one, loosing focus of the old input. The problem was that i wrote a custom form component, which cloned all child inputs via mapChildren.

However, the suggested defaultValue prop works just fine, still I wonder how a solution could look like that would keep the eventual inputs in place.

I have a case where I fetch content from CMS which contains HTML forms.
Those forms are displayed as a part of react application and inputs don't work (because of this issue).

HTML forms are directly appended, in other words no iframe (can't use iframe).

Is there a workaround for React to ignore value attribute?

Thank you very much for your help in advance.

I don't understand how you're displaying HTML "in React" and encounter this issue. Can you share a small example?

Sure - https://stackblitz.com/edit/react-bxzsrz

Nevertheless, seems like there is something to ReactHtmlParser library. If I use it to parse HTML Content it freezes the input. On the other hand, when using dangerouslySetInnerHTML method everything works perfectly.

I know that this third party library, but maybe you can help to get an idea why this is happening?

Anyways, that was my fault saying that code doesn't work because of this issue. Sorry for setting the fire here.

Nevertheless, seems like there is something to ReactHtmlParser library. If I use it to parse HTML Content it freezes the input.

Seems like ReactHtmlParser shouldn't use value as a controlled attribute, and should instead convert it to defaultValue. Please file an issue with them. Thanks!

I tried to get around using state, and used a class variable, because state would recreate ALL children, hence typing resulted superslow... For recreating children on props change I found a good way to get around my problem that is using a new ValuesContext for each Form, having each field inside ValueContext.Consumer, then i can recreate via clone those only when props or values have changes.

Sorry, it's very hard to understand what your problem is from a short description, or why this solution helped you, without specific code examples. It will just confuse future readers. If you see a specific bug in React please file a new issue with a reproducing example. For now I'll lock this to avoid future confusion.

Was this page helpful?
0 / 5 - 0 ratings