React - 用JavaScript设置输入值不会触发'onChange'事件

9
在我的React应用程序(版本15.4.2)中,我使用JavaScript更新文本输入字段的值 - 但是,我将字段与onChange事件监听器相关联,更改输入字段的值不会触发处理程序(当然,传统的在输入字段中打字可以),尽管字段的内容已正确更新。
constructor(props) {
    super(props);
    this.onChange = this.onChange.bind(this);
}

onChange(event){
    let attribute = event.target.name;
    let updatedGroup = this.state.group;
    updatedGroup[attribute] = event.target.value;
    this.setState({group: updatedGroup});
}

addMember(memberId) {
    let inputField = document.getElementById("members");
    let inputValues = inputField.value.split(",");
    inputField.value = [...inputValues, memberId];
}

render(){
    <input type="text" id="members" name="members" value={this.state.group.members} onChange={this.onChange} />
}

当调用addMember()函数(通过子组件中的按钮单击)时,输入框本身的内容将被正确更新,但onChange不会被调用,因此状态不会被更新等等...

有没有一种方法可以编程方式设置输入框的值并触发onChange


1
你能提供更多关于你正在尝试做什么以及为什么要这样做的上下文吗?addMember()是你正在公开的公共方法吗?为什么你需要使用方法而不是简单地传递props?在React中,你应该抵制直接操作DOM的冲动,就像你现在所做的那样。也就是说,在这里使用document.getElementById是没有必要的。 - ericgio
我对React还比较新,所以可能不是以最佳方式操作。基本上,文本输入是用户ID的字符串(来自数组)-“2,46,3”等。当应用程序用户从列表中点击某个用户的名称时,将触发addMember函数,并将其ID添加到输入列表中,以便状态(最终,数据库)将被更新以反映此新用户。 - skwidbreth
但我明白你的意思 - 你给了我一些值得思考的东西。 - skwidbreth
2个回答

2
在这种情况下,我通常会将您的 onChange 事件处理程序设置为一个将事件数据(输入的字符或聚合字符串)传递到另一个函数的函数。 我将所有业务逻辑放在那个函数中。 这样,如果我想调用业务逻辑,只需调用该方法。
既然您正在问“是否有一种可以编程设置输入字段的值并触发 onChange 的方法?”,为什么不跳过 onChange 并从程序化设置值的函数中调用业务逻辑函数呢?

1
是的,我明白你的意思 - 现在已经有点晚了,但我打算明早尝试这种方法 - 谢谢! - skwidbreth
1
这是我强烈推荐的一种模式。将业务逻辑与视图逻辑完全分离。此外,使用TypeScript。它就像JavaScript但更好!而且它可以编译成JavaScript。 - joe_coolish
非常感谢您的想法 - 我是React的新手,所以我正在逐渐习惯这种思维方式,非常有帮助。 - skwidbreth
这种模式在 React 之外的许多场景中都很好用。另外,你有没有研究过 React + Redux? - joe_coolish

1

Onchange 方法只有在您输入文本时才会触发,如果您使用 document.getElementById 并替换其值,则它将直接替换 DOM 中的值,在这种情况下,onChange 将不会被触发。由于您正在使用 React,我认为您应该避免直接操作 DOM。

您正在使用受控输入,因此在 addMember 方法中,不要更新 DOM 中的值,而是更新 state 值。

尝试这个 addmember 方法:

addMember(memberId) {
    //let inputField = document.getElementById("members");
    //let inputValues = inputField.value.split(",");
    //inputField.value = [...inputValues, memberId];

    let group = this.state.group.slice();
    group[members] = group[members] + ',' + memberId;
    this.setState({
        group
    });
}

抱歉,我应该明确说明 - 那是在构造函数中设置的 - 我会编辑我的问题以反映这一点。 - skwidbreth
你把控制台放在了onchange方法里吗?它没有打印控制台的值吗? - Mayank Shukla
是的,我尝试在onChange方法中放置一个console.log("test"),它只会在我在文本字段中输入时记录日志,但如果通过调用addMember()更改值,则不会记录日志。 - skwidbreth
谢谢!我是React的新手,这很有帮助。 - skwidbreth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接