使用 React 创建的表单不会更新支持状态对象
Form created with React doesn't update the backing state object
我正在尝试自动化Instagram网络应用程序的登录表单:
https://instagram.com/accounts/login/
使用以下代码(您可以在 Chrome 控制台上运行它):
var frm = window.frames[1].document.forms[0];
frm.elements[0].value = 'qacitester';
frm.elements[1].value = 'qatester';
frm.elements[2].click();
即使填充了输入,当我监视 XHR 请求时,我看到以下内容已发布:
用户名=&密码=&意图=
而不是这个:
用户名=qacitester&password=qatest&intent=
并导致 Web 应用无法进行身份验证。你知道为什么输入值没有转移到 React 的支持状态(模型?)对象吗?
Instagram正在使用ReactLink的linkState
方法:
http://facebook.github.io/react/docs/two-way-binding-helpers.html
登录页面链接到包含压缩代码的bundles/Login.js
,如下所示:
o.createElement("input", {
className:"lfFieldInput",
type:"text",
name:"username",
maxLength:30,
autoCapitalize:!1,
autoCorrect:!1,
valueLink:this.linkState("username")
}))
如果您查看 ReactLink 的文档,这意味着输入字段值只有在输入字段上触发更改事件时才会发送回状态。但是,这并不像在相关节点上触发更改事件那么简单 - 我认为是由于 React 规范化浏览器事件的方式。React 文档特别指出,由于各种原因,React 中的 onChange 与浏览器中的 onChange 并不完全相同:
http://facebook.github.io/react/docs/dom-differences.html
幸运的是,在您的情况下,Instagram正在使用包含插件的React,这使您可以访问React TestUtils,因此您可以执行以下操作:
var frm = window.frames[1].document.forms[0];
var fReact = window.frames[1].React;
fReact.addons.TestUtils.Simulate.change(frm.elements[0], {target: {value: 'qacitester' }});
fReact.addons.TestUtils.Simulate.change(frm.elements[1], {target: {value: 'qatester' }});
frm.elements[2].click();
更多文档在这里:
http://facebook.github.io/react/docs/test-utils.html
请注意,由于登录表单本身位于 iframe 中,因此您必须使用该 iframe 中的 React 实例,否则 TestUtils 将无法正确找到节点。
这仅适用于页面上包含 React 插件的情况。React 的正常非插件构建将需要另一种解决方案。但是,如果您专门谈论 ReactLink,那么无论如何这是一个插件,所以这不是问题。
回答我自己的问题,所需的事件似乎是输入事件,并且此代码有效:
var doc = window.frames[1].document;
var frm = doc.forms[0];
frm.elements[0].value = 'qacitester';
var evt = doc.createEvent('UIEvent');
evt.initUIEvent('input', true, false);
frm.elements[0].dispatchEvent(evt);
frm.elements[1].value = 'qatester';
frm.elements[1].dispatchEvent(evt);
frm.elements[2].click();
登录表单实际上位于iFrame中,这使事情变得更加复杂。我能够从chrome控制台成功提交运行以下代码的登录名。我正在使用 React 的 TestUtils,但你可能对 AutoType 没问题:
// run in Chrome console
var frame = document.querySelector('iframe[src*="login"]');
var s = document.createElement('script');
var username = frame.contentDocument.querySelector('input[name="username"]');
var password = frame.contentDocument.querySelector('input[name="password"]');
s.src = "https://fb.me/react-with-addons-0.12.0.js";
frame.contentDocument.body.appendChild(s);
// wait for the script request to resolve and use:
change = frame.contentWindow.React.addons.TestUtils.Simulate.change;
change(username, {target: {value: 'My Great Username'}});
change(password, {target: {value: 'securepassword'}});
背景
React 使用自己的虚拟事件系统,并且通常使用受控组件,这本质上意味着输入value
由 react 设置并向下渗透到 DOM 元素。
考虑到这一点,我相信您遇到的问题是因为 react 在输入上查找关键事件,并使用事件发生时的输入值来设置 DOM 元素的值。由于您只是设置 DOM 元素的 value
属性,因此您正在打破受控组件循环。
我做了一个快速的峰值,试图在输入上调度一个KeyboardEvent
,但唉,它没有成功。如果我确实成功了,我会更新我的答案。
不令人满意的解决方法:
使用 casper/phantomjs 自动填写表单。这意味着您不必担心自己调度事件,您可以让"浏览器"为您完成。这也比在控制台中手动工作要好。
- Javascript循环不会自我更新
- 添加文字和评论功能更新Div
- AngularJS:ng之后,重复$scope值未按预期更新
- 如何通过数组更新角度子范围
- Ajax聊天消息重复而不仅仅是更新
- 通过CSV文件上载更新数据库表
- 平均值:无法将数据更新到数据库
- $rootScope未使用forEach进行更新
- d3基于用户选择动态更新节点
- jQuery-2.1.1.min.js或最新版本jQuery-2.13.min.js不会't支持'@
- 有条件更新d3.js力图中节点的最佳方法
- Angular:更新一次性绑定的数据
- Javascript更新孙窗口中的表单元素
- 使用 React 创建的表单不会更新支持状态对象
- 支持SEO的部分更新
- 如何在netsuite上使用用户事件suitescript更新不支持的事务类型(如Bill)的字段
- 在没有 jQuery 支持的情况下更新 javascript 中的本地存储值
- Mongoose似乎不支持$max字段更新操作符,有什么建议吗?
- Visual Studio 2015 RTM -在更新TypeScript工具后失去对JavaScript的支持
- Cordova vs Phonegap关于插件,支持,文档,更新