在react js中触发onchange事件的最佳方法是什么

IT技术 reactjs
2021-03-23 00:18:05

我们使用 Backbone + ReactJS bundle 来构建客户端应用程序。严重依赖臭名昭著的valueLink我们通过自己的包装器将值直接传播到模型,该包装器支持用于双向绑定的 ReactJS 接口。

现在我们面临的问题是:

我们有jquery.mask.js以编程方式格式化输入值的插件,因此它不会触发 React 事件。所有这些都会导致模型从用户输入接收未格式化的值而从插件中丢失格式化的

似乎 React 有很多取决于浏览器的事件处理策略。有没有什么通用的方法可以触发特定 DOM 元素的更改事件,以便 React 能够听到它?

6个回答

对于 React 16 和 React >=15.6

Setter.value=没有按我们想要的方式工作,因为 React 库覆盖了输入值 setter,但我们可以直接在inputas 上下文中调用该函数

var nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
nativeInputValueSetter.call(input, 'react 16 value');

var ev2 = new Event('input', { bubbles: true});
input.dispatchEvent(ev2);

对于textarea元素,你应该使用prototypeHTMLTextAreaElement类。

新的代码笔示例

所有学分这个贡献者他的解决方案

仅适用于 React <=15.5 的过时答案

有了react-dom ^15.6.0您可以使用simulated标志事件对象的事件经过

var ev = new Event('input', { bubbles: true});
ev.simulated = true;
element.value = 'Something new';
element.dispatchEvent(ev);

用一个例子做了一个代码笔

为了理解为什么需要新标志,我发现这条评论非常有帮助:

React 中的输入逻辑现在对更改事件进行重复数据删除,因此每个值不会触发超过一次。它侦听浏览器 onChange/onInput 事件以及 DOM 节点值 prop 上的设置(当您通过 javascript 更新值时)。这意味着如果你手动更新输入的值 input.value = 'foo' 然后使用 { target: input } 调度 ChangeEvent react将注册集合和事件,看到它的值仍然是''foo ',将其视为重复事件并吞下它。

这在正常情况下工作正常,因为“真实”浏览器启动的事件不会触发 element.value 上的设置。您可以通过使用模拟标志标记您触发的事件来秘密地摆脱这种逻辑,并且 react 将始终触发该事件。 https://github.com/jquense/react/blob/9a93af4411a8e880bbc05392ccf2b195c97502d1/src/renderers/dom/client/eventPlugins/ChangeEventPlugin.js#L128

按钮 onClick 怎么样?应该怎么做才能触发这种事件?
2021-06-03 00:18:05
感谢这在 react-dom ^15.6.0 中确实有效。但似乎在 React 16.0 之后这已经停止工作了。关于使用模拟标志触发更改事件的替代方法的任何想法?
2021-06-05 00:18:05
@Qwerty 我更新了我的答案,可能对你有用
2021-06-05 00:18:05
@Bender 您只需在元素上调用本机单击方法
2021-06-16 00:18:05
相信这里有一点可以给出提示:reactjs.org/blog/2017/09/26/react-v16.0.html#break-changes知道它可能是什么吗?
2021-06-18 00:18:05

至少在文本输入上,它似乎onChange在监听输入事件:

var event = new Event('input', { bubbles: true });
element.dispatchEvent(event);
2021-06-01 00:18:05
取决于浏览器版本。IE8 不支持输入事件。当您从文本框中删除字符时,ie9 不会触发输入事件。developer.mozilla.org/en-US/docs/Web/Events/input
2021-06-03 00:18:05
@Michael 我正在 IE11 上尝试您的代码,但它不适用于 reactjs 输入字段。它确实适用于普通的 HTML 输入。它也适用于 Edge。var evt = document.createEvent('CustomEvent'); evt.initCustomEvent('input', true, false, { }); document.getElementById('description').value = 'I changed description'; document.getElementById('description').dispatchEvent(evt);
2021-06-05 00:18:05
React不再支持IE8 。对于 IE9,您可能可以使用类似var event = document.createEvent('CustomEvent'); event.initCustomEvent('input', true, false, { });,但我手边没有 IE9 VM。
2021-06-16 00:18:05

我知道这个答案来得有点晚,但我最近遇到了类似的问题。我想在嵌套组件上触发一个事件。我有一个包含单选和复选框类型小部件的列表(它们是行为类似于复选框和/或单选按钮的 div),在应用程序的其他地方,如果有人关闭了一个工具箱,我需要取消选中一个。

我找到了一个非常简单的解决方案,不确定这是否是最佳实践,但它有效。

var event = new MouseEvent('click', {
 'view': window, 
 'bubbles': true, 
 'cancelable': false
});
var node = document.getElementById('nodeMyComponentsEventIsConnectedTo');
node.dispatchEvent(event);

这触发了 domNode 上的点击事件,我通过 react 附加的处理程序确实被调用了,所以它的行为就像我期望的那样,如果有人点击了元素。我没有测试过 onChange 但它应该可以工作,并且不确定这在 IE 的真正旧版本中如何公平,但我相信 MouseEvent 至少在 IE9 及更高版本中受支持。

对于我的特定用例,我最终放弃了这个,因为我的组件非常小(只有我的应用程序的一部分使用了 react,因为我还在学习它)而且我可以用另一种方式实现同​​样的事情,而无需获取对 dom 节点的引用。

更新:

正如其他人在评论中所说的那样,最好使用this.refs.refname来获取对 dom 节点的引用。在这种情况下, refname 是您通过<MyComponent ref='refname' />.

您可以使用该React.findDOMNode函数代替 ID goo.gl/RqccrA
2021-05-27 00:18:05
框架很可能已经改变了,它的 this.ref s .refname
2021-06-13 00:18:05
字符串引用现在被认为是遗留的,将来会被弃用。回调引用是跟踪 DOM 节点的首选方法。
2021-06-15 00:18:05
>您可以使用 React.findDOMNode 函数代替 ID。或添加ref到您的元素然后使用this.ref.refName.dispatchEvent
2021-06-18 00:18:05

扩展 Grin/Dan Abramov 的答案,这适用于多种输入类型。在 React >= 15.5 中测试

const inputTypes = [
    window.HTMLInputElement,
    window.HTMLSelectElement,
    window.HTMLTextAreaElement,
];

export const triggerInputChange = (node, value = '') => {

    // only process the change on elements we know have a value setter in their constructor
    if ( inputTypes.indexOf(node.__proto__.constructor) >-1 ) {

        const setValue = Object.getOwnPropertyDescriptor(node.__proto__, 'value').set;
        const event = new Event('input', { bubbles: true });

        setValue.call(node, value);
        node.dispatchEvent(event);

    }

};
不适用于选择元素。对于事件,您需要“更改”而不是“输入”。
2021-06-08 00:18:05

您可以使用ReactTestUtils模拟事件,但它是为单元测试而设计的。

我建议不要在这种情况下使用 valueLink,而只是监听插件触发的更改事件并更新输入的状态作为响应。双向绑定实用程序更像是一个演示,而不是其他任何东西;它们包含在插件中只是为了强调这样一个事实,即纯双向绑定不适用于大多数应用程序,并且您通常需要更多应用程序逻辑来描述应用程序中的交互。

而且...如果您想使用 ReactTestUtils... ReactTestUtils.Simulate.change(ReactDOM.findDOMNode(this.fieldRef))
2021-05-31 00:18:05
我担心答案会是这样的(。问题是 React 对发送/接收工作流程太严格了。特别是必须指定 onChange 处理程序才能对用户输入做出反应,除了不受控制的状态之外别无他法超过样板给我。在我的情况下,我应该声明这个处理程序只遵循规则,而相关输入将来自 jquery 触发的 onchange 事件。React 真的缺乏使用用户声明的代码扩展发送/接收端点的想法
2021-06-15 00:18:05