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.
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.
Most helpful comment
If you specify
value
the input becomes "controlled". This means you _must_ update the corresponding state inonChange
. In React,value={something}
literally means "value will always besomething
no matter what".So you probably want to call
inside your
onChange
handler.Alternatively, you can remove the
value
prop altogether and make an input "uncontrolled". Then you won't have to callsetState()
, 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?