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

后端 未结 9 1840
我在风中等你
我在风中等你 2020-11-30 04:34

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

相关标签:
9条回答
  • 2020-11-30 04:54

    I think you should change that like so:

    <input value={this.state.value} onChange={(e) => {this.handleChange(e)}}/>
    

    That is in principle the same as onClick={this.handleClick.bind(this)} as you did on the button.

    So if you want to call handleChange() when the button is clicked, than:

    <button onClick={this.handleChange.bind(this)}>Change Input</button>
    

    or

    handleClick () {
      this.setState({value: 'another random text'});
      this.handleChange();
    }
    
    0 讨论(0)
  • 2020-11-30 05:02

    I know what you mean, you want to trigger handleChange by click button.

    But modify state value will not trigger onChange event, because onChange event is a form element event.

    0 讨论(0)
  • 2020-11-30 05:06

    Solution Working in the Year 2020:

    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

    0 讨论(0)
  • 2020-11-30 05:06

    Try this code if state object has sub objects like this.state.class.fee. We can pass values using following code:

    this.setState({ class: Object.assign({}, this.state.class, { [element]: value }) }
    
    0 讨论(0)
  • 2020-11-30 05:08

    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.

    0 讨论(0)
  • 2020-11-30 05:08

    Approach with React Native and Hooks:

    You can wrap the TextInput into a new one that watches if the value changed and trigger the onChange function if it does.

    import React, { useState, useEffect } from 'react';
    import { View, TextInput as RNTextInput, Button } from 'react-native';
    
    // New TextInput that triggers onChange when value changes.
    // You can add more TextInput methods as props to it.
    const TextInput = ({ onChange, value, placeholder }) => {
    
      // When value changes, you can do whatever you want or just to trigger the onChange function
      useEffect(() => {
        onChange(value);
      }, [value]);
    
      return (
        <RNTextInput
          onChange={onChange}
          value={value}
          placeholder={placeholder}
        />
      );
    };
    
    const Main = () => {
    
      const [myValue, setMyValue] = useState('');
    
      const handleChange = (value) => {
        setMyValue(value);
        console.log("Handling value");
      };
    
      const randomLetters = [...Array(15)].map(() => Math.random().toString(36)[2]).join('');
    
      return (
        <View>
          <TextInput
            placeholder="Write something here"
            onChange={handleChange}
            value={myValue}
          />
          <Button
            title='Change value with state'
            onPress={() => setMyValue(randomLetters)}
          />
        </View>
      );
    };
    
    export default Main;
    
    0 讨论(0)
提交回复
热议问题