Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React: trigger onChange if input value is changing by state?

Edit: I don't want to call handleChange only if the button has been clicked. It has nothing to do with handleClick. I gave an example in the @shubhakhatri answer's comment.

I want to change the input value according to state, the value is changing but it doesn't trigger handleChange() method. How can I trigger handleChange() method ?

class App extends React.Component {   constructor(props) {     super(props)     this.state = {     value: 'random text'     }   }   handleChange (e) {     console.log('handle change called')   }   handleClick () {     this.setState({value: 'another random text'})   }   render () {     return (       <div>         <input value={this.state.value} onChange={this.handleChange}/>         <button onClick={this.handleClick.bind(this)}>Change Input</button>       </div>     )   } }  ReactDOM.render(<App />,  document.getElementById('app')) 

Here is the codepen link: http://codepen.io/madhurgarg71/pen/qrbLjp

like image 546
madhurgarg Avatar asked Mar 02 '17 08:03

madhurgarg


People also ask

What happens when state is updated in React?

State updates in React are asynchronous; when an update is requested, there is no guarantee that the updates will be made immediately. The updater functions enqueue changes to the component state, but React may delay the changes, updating several components in a single pass.

How do you get the value of change in React?

To get the value of an input on change in React, set an onChange event handler on the input, then use the target. value property of the Event object passed to the handler to get the input value. The message is updated when the input value changes.


2 Answers

You need to trigger the onChange event manually. On text inputs onChange listens for input events.

So in you handleClick function you need to trigger event like

handleClick () {     this.setState({value: 'another random text'})     var event = new Event('input', { bubbles: true });     this.myinput.dispatchEvent(event);   } 

Complete code

class App extends React.Component {   constructor(props) {     super(props)     this.state = {     value: 'random text'     }   }   handleChange (e) {     console.log('handle change called')   }   handleClick () {     this.setState({value: 'another random text'})     var event = new Event('input', { bubbles: true });     this.myinput.dispatchEvent(event);   }   render () {     return (       <div>         <input readOnly value={this.state.value} onChange={(e) => {this.handleChange(e)}} ref={(input)=> this.myinput = input}/>         <button onClick={this.handleClick.bind(this)}>Change Input</button>       </div>     )   } }  ReactDOM.render(<App />,  document.getElementById('app')) 

Codepen

Edit: As Suggested by @Samuel in the comments, a simpler way would be to call handleChange from handleClick if you don't need to the event object in handleChange like

handleClick () {     this.setState({value: 'another random text'})     this.handleChange();   } 

I hope this is what you need and it helps you.

like image 108
Shubham Khatri Avatar answered Sep 24 '22 09:09

Shubham Khatri


I tried the other solutions and nothing worked. This is because of input logic in React.js has been changed. For detail, you can see this link: https://hustle.bizongo.in/simulate-react-on-change-on-controlled-components-baa336920e04.

In short, when we change the value of input by changing state and then dispatch a change event then React will register both the setState and the event and consider it a duplicate event and swallow it.

The solution is to call native value setter on input (See setNativeValue function in following code)

Example Code

import React, { Component } from 'react' export class CustomInput extends Component {      inputElement = null;          // THIS FUNCTION CALLS NATIVE VALUE SETTER     setNativeValue(element, value) {         const valueSetter = Object.getOwnPropertyDescriptor(element, 'value').set;         const prototype = Object.getPrototypeOf(element);         const prototypeValueSetter = Object.getOwnPropertyDescriptor(prototype, 'value').set;          if (valueSetter && valueSetter !== prototypeValueSetter) {             prototypeValueSetter.call(element, value);         } else {             valueSetter.call(element, value);         }     }       constructor(props) {         super(props);          this.state = {             inputValue: this.props.value,         };     }      addToInput = (valueToAdd) => {         this.setNativeValue(this.inputElement, +this.state.inputValue + +valueToAdd);         this.inputElement.dispatchEvent(new Event('input', { bubbles: true }));     };      handleChange = e => {         console.log(e);         this.setState({ inputValue: e.target.value });         this.props.onChange(e);     };      render() {         return (             <div>                 <button type="button" onClick={() => this.addToInput(-1)}>-</button>                 <input                     readOnly                     ref={input => { this.inputElement = input }}                     name={this.props.name}                     value={this.state.inputValue}                     onChange={this.handleChange}></input>                 <button type="button" onClick={() => this.addToInput(+1)}>+</button>             </div>         )     } }  export default CustomInput 

Result

enter image description here

like image 28
Muhammad Inaam Munir Avatar answered Sep 25 '22 09:09

Muhammad Inaam Munir