React:以编程方式更改组件值不会触发onChange事件

时间:2017-05-09 16:16:07

标签: reactjs

我在React组件中有一个select字段,它通过组件状态赋值,并且有一个附加到onChange事件的函数。如果我手动更改选择字段值,则会触发onChange事件,但如果我通过更改其他函数的状态值来更改它,则不会。有没有办法以编程方式触发事件?

修改

以下是我需要实现的基本示例。想法是当handleChange1()更改state.val2的值(因此更改在第二个选择字段上选择的选项)时,handleChange2()也会被触发,因此合成事件将传递给父函数(在实际中)代码,选择字段是另一个组件):

class Component extends React.Component {
  state = {
    val1: 1,
    val2: 1,
  }

  handleChange1 = (event) => {
    const val2 = event.target.value === 3 ? 1 : null;
    this.setState({
      val1: event.target.value,
    });
    if (event.target.value === 3) {
      this.setState({
        val2: 1,
      });
    }
    this.props.parentFunction(event);
  }

  handleChange2 = (event) => {
    this.setState({
      val2: event.target.value,
    });
    this.props.parentFunction(event);
  }

  render() {
    return (
        <div>
          <select value={val1} onChange={this.handleChange1}>
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
          </select>
          <select value={val2} onChange={this.handleChange2}>
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="3">3</option>
          </select>
        </div>
    );
  }
};

3 个答案:

答案 0 :(得分:1)

您应该将输入包装在专用组件中以自定义所需的行为。类似的东西:

class Input extends React.Component {

 constructor(props){
    super(props);
    this.state = {
      value: props.value
    }
  }

  componentWillReceiveProps(nextProps) {
    this.setState({
      value: nextProps.value,
    });
    this.props.onChange(nextProps.value);
  }

  updateValue(ev) {
    this.setState({
      value: ev.target.value,
    });
    this.props.onChange(ev.target.value);
  }

  render() {
    return (
      <input
        onChange={this.updateValue.bind(this)}
        value={this.state.value}
        {...this.props}
      />
    )
  }
}

并使用它:

<Input value="test" onChange={someAction} />

请注意,由于您的输入处于受控状态,因此值绝不能为null或未定义。

答案 1 :(得分:1)

是的,有办法! React的逻辑可以防止通过编程设置输入值时触发onChange,但是可以解决。

代替:

input.value = 'foo';

执行此操作:

const setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
setter.call(input, 'foo');
input.dispatchEvent(new Event('input', { bubbles: true }));

查看this article以获得完整说明。


如果不清楚,input的值是您将从引用中获取的DOM元素。示例:

function SomeComponent({ onChange }) {
  const ref = useRef();

  useEffect(() => {
    setInterval(() => {
      const input = ref.current;
      const setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
      setter.call(input, new Date().toISOString());
      input.dispatchEvent(new Event('input', { bubbles: true }));
    }, 10000);
  });

  return <input type="text" ref="ref" onChange={onChange} />;
}

此组件将使用日期字符串更新其输入,并每10秒使用新值触发onChange回调。

答案 2 :(得分:0)

我遇到了同样的问题,很幸运, @gouroujo 的答案对我有用,但是当我检查文档时,其名称已更改为UNSAFE_componentWillReceiveProps(),文档说:

  

注意

     

此生命周期以前称为 componentWillReceiveProps 。该名称将一直使用到第17版。请使用rename-unsafe-lifecycles codemod自动更新您的组件。

More details about UNSAFE_componentWillReceiveProps()

另一种解决方案是在组件上设置key,以便反应可以

  

创建一个新的组件实例,而不是更新当前实例。

More details about Fully uncontrolled component with a key