35

I have the following input field as below. On blur, the function calls a service to update the input value to the server, and once that's complete, it updates the input field.

How can I make it work? I can understand why it's not letting me change the fields but what can I do to make it work?

I can't use the defaultValue because I will be changing these fields to some other ones

<input value={this.props.inputValue} onBlur={this.props.actions.updateInput} />

Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
Suthan Bala
  • 3,209
  • 5
  • 34
  • 59

3 Answers3

50

In order to have the input value editable you need to have an onChange handler for it that updates the value. and since you want to call a function onBlur, you have to bind that like onBlur={() => this.props.actions.updateInput()}

componentDidMount() {
   this.setState({inputValue: this.props.inputValue});
}
handleChange = (e) => {
  this.setState({inputValue: e.target.value});
}

<input value={this.state.inputValue} onChange={this.handlechange} onBlur={() => this.props.actions.updateInput(this.state.inputValue)} />
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • 2
    What if you want to use onBlur that dispatches the updated value to the state - without having to use onChange to re-render the component on every keystroke? – Delice May 02 '21 at 21:40
  • @Delice you can do that but will have to make the input element uncontrolled by not setting its value from state – Shubham Khatri May 03 '21 at 04:40
  • Is there way to achieve the controlled component but with the functionality like onBlur in order to prevent unnecessary re-render of other child components? – Delice May 03 '21 at 07:17
  • Sorry, but this answer may introduce race conditions because setState is not synchronous.. – Tasos May 05 '22 at 10:10
13

Ways of doing this:

  1. Do not assign value property to input field, whenever onblur method gets trigger, hit the api like this:

    <input placeholder='abc' onBlur={(e)=>this.props.actions.updateInput(e.target.value)} />
    

Update value to server:

updateInput(value){
    /*update the value to server*/
}
  1. If you are assigning the value property to input field by this.props.inputValue, then use onChange method, pass the value back to parent component, change the inputValue by using setState in parent, it will work like this:

    <input value={this.props.inputValue} onChange={(e)=>this.props.onChange(e.target.value)} onBlur={()=>this.props.actions.updateInput} />
    

In Parent Component:

onChange(value){
    this.setState({inputvalue:value});
}

Update value to server:

updateInput(value){
    /*update the value to server*/
}
Mayank Shukla
  • 100,735
  • 18
  • 158
  • 142
5

You will want to bind a onChange event to update your state. Make sure to use the bind method in your constructor so that you do not lose the 'this' context within your onChange event handler method. You will then want to pass the value back to your update input method onBlur. Something like this:

constructor(props) {
  super(props);

  this.state = {
    inputValue: props.inputValue
  };
  this.handleChange = this.handleChange.bind(this);
};

handleChange = (e) => {
  this.setState({inputValue: e.target.value});
}

<input 
  value={this.state.inputValue}
  onChange={this.handleChange}
  onBlur={() => this.props.actions.updateInput(this.state.inputValue)} 
/>
MDiesel
  • 2,647
  • 12
  • 14
  • 4
    firstly setting props to initial state is an antipattern, and if you make use of arrow function you no funcger need bind in the constructor – Shubham Khatri Jan 24 '17 at 16:18