React:如果输入值按状态改变,则触发onChange?

时间:2017-03-02 08:32:03

标签: javascript reactjs

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

我想根据状态更改输入值,值正在改变,但它不会触发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'))

以下是codepen链接:http://codepen.io/madhurgarg71/pen/qrbLjp

11 个答案:

答案 0 :(得分:19)

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

所以在handleClick () { this.setState({value: 'another random text'}) var event = new Event('input', { bubbles: true }); this.myinput.dispatchEvent(event); } 函数中你需要触发像

这样的事件
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'))

完整代码

handleChange

<强> Codepen

编辑: 正如@Samuel在评论中所建议的那样,如果您handleClick中的don't need to the event object喜欢

,则可以从handleChange致电handleClick () { this.setState({value: 'another random text'}) this.handleChange(); } 更简单的方法
{{1}}

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

答案 1 :(得分:10)

2020年解决方案工作

我尝试了其他解决方案,但没有任何效果。这是因为React.js中的输入逻辑已被更改。有关详细信息,您可以查看以下链接:https://hustle.bizongo.in/simulate-react-on-change-on-controlled-components-baa336920e04

简而言之,当我们通过更改状态来更改输入的值,然后调度一个change事件时,React将同时注册setState和event并将其视为重复事件并吞下它。

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

示例代码

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

结果

enter image description here

答案 2 :(得分:5)

我认为你应该改变它:

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

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

因此,如果您想在单击按钮时调用handleChange(),而不是:

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

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

答案 3 :(得分:1)

handleChange被调用(&#39;处理更改称为&#39;在控制台中打印)但它不会更新状态。您必须在更改处理程序中更新状态:

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

并且您还必须将上下文绑定到处理程序:

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

答案 4 :(得分:1)

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

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

答案 5 :(得分:1)

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

  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.JBSwitchComponentDom.dispatchEvent(event);
    
  5. 上面代码yourComponentDomRef中的

    指的是您的React组件的主dom,例如<div className="component-root-dom" ref={(dom)=>{this.yourComponentDomRef= dom}}>

答案 6 :(得分:1)

其他答案则涉及渲染中的直接绑定,因此我想为此添加几点。

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

您应该如何操作类似于以下内容

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}/>

您还可以使用箭头功能,但是在某些情况下每次组件重新渲染时,箭头功能也会创建新功能。您应该知道何时使用箭头功能以及何时不应该使用箭头功能。有关何时使用箭头功能的详细说明,请查看接受的答案here

答案 7 :(得分:1)

如果状态对象具有this.state.class.fee之类的子对象,请尝试此代码。我们可以使用以下代码传递值:

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

答案 8 :(得分:0)

使用React Native和Hooks的方法:

您可以将TextInput包装为一个新的,监视值是否更改,并触发onChange函数。

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;

答案 9 :(得分:0)

在您可以执行此操作的功能组件中,假设我们有一个 input[type=number]

const MyInputComponent() => {
    const [numberValue, setNumberValue] = useState(0);
    const numberInput = useRef(null);

    /**
    * Dispatch Event on Real DOM on Change
    */
    useEffect(() => {
        numberInput.current.dispatchEvent(
            new Event("change", {
                detail: {
                    newValue: numberValue,
                },
                bubbles: true,
                cancelable: true,
            })
        );
    }, [numberValue]);

    return (
        <>
            <input    
                type="number"            
                value={numberValue}             
                ref={numberInput}
                inputMode="numeric"
                onChange={(e) => setNumberValue(e.target.value)}
            />
        </>
    )
}

答案 10 :(得分:-1)

我也有类似的需求,最终使用componentDidMount(),即在组件类构造函数之后调用(您可以在props中初始化状态-使用redux作为示例)

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

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

   componentDidMount() {

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

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

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