Javascript 反应:如果输入值因状态而变化,则触发 onChange?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/42550341/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 01:15:04  来源:igfitidea点击:

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

javascriptreactjs

提问by madhurgarg

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.

编辑:我不想仅在单击按钮时才调用 handleChange。它与 handleClick 无关。我在@shubhakhatri 回答的评论中举了一个例子。

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 ?

我想根据状态更改输入值,该值正在更改但它不会触发handleChange()方法。如何触发handleChange()方法?

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

这是代码笔链接:http://codepen.io/madhurgarg71/pen/qrbLjp

回答by Shubham Khatri

You need to trigger the onChangeevent manually. On text inputs onChange listens for inputevents.

您需要onChange手动触发事件。在文本输入上 onChange 监听input事件。

So in you handleClickfunction you need to trigger event like

所以在你的handleClick函数中你需要触发事件

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 handleChangefrom handleClickif you don't need to the event objectin handleChangelike

编辑:正如@Samuel 在评论中所建议的,一种更简单的方法是调用handleChangefrom handleClickif you don't need to the event objectin handleChangelike

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

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

我希望这是你需要的,它可以帮助你。

回答by philipp

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.

原则上与onClick={this.handleClick.bind(this)}您在按钮上所做的相同。

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

因此,如果您想在handleChange()单击按钮时调用,请执行以下操作:

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

or

或者

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

回答by Muhammad Inaam Munir

Solution Working in the Year 2020:

在 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.

我尝试了其他解决方案,但没有任何效果。这是因为 React.js 中的输入逻辑已更改。有关详细信息,您可以查看此链接: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.

简而言之,当我们通过改变 state 来改变 input 的值,然后调度 change 事件时,React 将同时注册 setState 和事件,并将其视为重复事件并吞下它。

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

解决方案是在输入上调用本机值设置器(请参阅以下代码中的 setNativeValue 函数)

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

在此处输入图片说明

回答by javad bat

you must do 4 following step :

您必须执行以下 4 个步骤:

  1. create event

    var event = new Event("change",{
        detail: {
            oldValue:yourValueVariable,
            newValue:!yourValueVariable
        },
        bubbles: true,
        cancelable: true
    });
    event.simulated = true;
    let tracker = this.yourComponentDomRef._valueTracker;
    if (tracker) {
        tracker.setValue(!yourValueVariable);
    }
    
  2. bind value to component dom

    this.yourComponentDomRef.value = !yourValueVariable;
    
  3. bind element onchange to react onChange function

     this.yourComponentDomRef.onchange = (e)=>this.props.onChange(e);
    
  4. dispatch event

    this.yourComponentDomRef.dispatchEvent(event);
    
  1. 创建事件

    var event = new Event("change",{
        detail: {
            oldValue:yourValueVariable,
            newValue:!yourValueVariable
        },
        bubbles: true,
        cancelable: true
    });
    event.simulated = true;
    let tracker = this.yourComponentDomRef._valueTracker;
    if (tracker) {
        tracker.setValue(!yourValueVariable);
    }
    
  2. 将值绑定到组件 dom

    this.yourComponentDomRef.value = !yourValueVariable;
    
  3. 绑定元素 onchange 以响应 onChange 函数

     this.yourComponentDomRef.onchange = (e)=>this.props.onChange(e);
    
  4. 分派事件

    this.yourComponentDomRef.dispatchEvent(event);
    

in above code yourComponentDomRefrefer to master dom of your React component for example <div className="component-root-dom" ref={(dom)=>{this.yourComponentDomRef= dom}}>

在上面的代码中yourComponentDomRef,例如参考你的 React 组件的 master dom<div className="component-root-dom" ref={(dom)=>{this.yourComponentDomRef= dom}}>

回答by Hemadri Dasari

The other answers talked about direct binding in render hence I want to add few points regarding that.

其他答案讨论了渲染中的直接绑定,因此我想补充几点。

You are not recommended to bind the function directly in render or anywhere else in the component except in constructor. Because for every function binding a new function/object will be created in webpack bundle js file hence the bundle size will grow. Your component will re-render for many reasons like when you do setState, new props received, when you do this.forceUpdate()etc. So if you directly bind your function in render it will always create a new function. Instead do function binding always in constructor and call the reference wherever required. In this way it creates new function only once because constructor gets called only once per component.

不建议您直接在 render 或组件中的任何其他地方(构造函数除外)绑定函数。因为对于每个函数绑定,都会在 webpack 包 js 文件中创建一个新的函数/对象,因此包的大小会增加。您的组件将出于多种原因重新渲染,例如何时执行 setState、收到新道具、何时执行this.forceUpdate()等。因此,如果您直接在渲染中绑定您的函数,它将始终创建一个新函数。而是始终在构造函数中进行函数绑定,并在需要时调用引用。通过这种方式,它只创建一次新函数,因为每个组件只调用一次构造函数。

How you should do is something like below

你应该怎么做,如下所示

constructor(props){
  super(props);
  this.state = {
    value: 'random text'
  }
  this.handleChange = this.handleChange.bind(this);
}

handleChange (e) {
  console.log('handle change called');
  this.setState({value: e.target.value});
}

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

You can also use arrow functions but arrow functions also does create new function every time the component re-renders in certain cases. You should know about when to use arrow function and when are not suppose to. For detailed explation about when to use arrow functions check the accepted answer here

您也可以使用箭头函数,但在某些情况下,每次组件重新渲染时,箭头函数也会创建新函数。你应该知道什么时候使用箭头函数,什么时候不应该使用。有关何时使用箭头函数的详细说明,请在此处查看接受的答案

回答by Atchutha rama reddy Karri

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

如果状态对象具有像this.state.class.fee. 我们可以使用以下代码传递值:

this.setState({ class: Object.assign({}, this.state.class, { [element]: value }) }

回答by mariano_c

I had a similar need and end up using componentDidMount(), that one is called long after component class constructor (where you can initialize state from props - as an exmple using redux )

我有类似的需求并最终使用了 componentDidMount(),在组件类构造函数之后很久才调用该构造函数(您可以在其中从 props 初始化状态 - 例如使用 redux )

Inside componentDidMount you can then invoke your handleChange method for some UI animation or perform any kind of component properties updates required.

在 componentDidMount 中,您可以为某些 UI 动画调用 handleChange 方法或执行所需的任何类型的组件属性更新。

As an example I had an issue updating an input checkbox type programatically, that's why I end up using this code, as onChange handler was not firing at component load:

例如,我在以编程方式更新输入复选框类型时遇到问题,这就是我最终使用此代码的原因,因为 onChange 处理程序未在组件加载时触发:

   componentDidMount() {

    // Update checked 
    const checkbox = document.querySelector('[type="checkbox"]');

    if (checkbox) 
      checkbox.checked = this.state.isChecked;
  }

State was first updated in component class constructor and then utilized to update some input component behavior

状态首先在组件类构造函数中更新,然后用于更新某些输入组件行为

回答by Xat_MassacrE

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

我知道你的意思,你想通过点击按钮触发 handleChange 。

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

但是修改状态值不会触发onChange事件,因为onChange事件是一个表单元素事件。