⚛️ 破解 React 受控组件:如何从外部脚本修改 Input 值?
摘要:在开发浏览器插件或自动化脚本时,你是否遇到过“修改了 input.value 但 React 状态没更新”的尴尬?本文教你一招破解 React 受控组件的限制。
问题复现
假设有一个 React 组件:
function App() {
const [val, setVal] = useState("");
return <input value={val} onChange={e => setVal(e.target.value)} />;
}
如果你在控制台运行:
document.querySelector('input').value = 'hello';
你会发现输入框里确实显示了 'hello',但是一旦你点击输入框,它又变回空了! 这是因为 React 的 state 并没有更新,重新渲染时又把 value 覆盖回去了。
原理分析
React 在底层劫持了 input 元素的 value setter。当你直接赋值时,React 内部的逻辑被绕过了。
而且,React 依赖 input 事件来更新 state。
AutoForm 的解决方案
在开发 AutoForm 智能填充 SDK 时,我们必须解决这个问题,否则无法支持 React 开发的系统。
我们需要做两件事:
- 调用原生 Setter:绕过 React 的劫持。
- 触发 Input 事件:通知 React 更新状态。
核心代码
function setNativeValue(element: HTMLInputElement, value: string) {
// 1. 获取原生的 value setter
const valueSetter = Object.getOwnPropertyDescriptor(element, 'value')?.set;
const prototype = Object.getPrototypeOf(element);
const prototypeValueSetter = Object.getOwnPropertyDescriptor(prototype, 'value')?.set;
// 2. 调用原生 setter
if (prototypeValueSetter && valueSetter !== prototypeValueSetter) {
prototypeValueSetter.call(element, value);
} else {
valueSetter?.call(element, value);
}
// 3. 触发 input 事件
element.dispatchEvent(new Event('input', { bubbles: true }));
}
进阶:处理复杂组件
对于 Ant Design 的 Select 或 DatePicker,它们往往由多个 DOM 元素组成(隐藏的 input + 模拟的 UI)。
这时候仅仅修改 input 是不够的。
AutoForm 的策略是:模拟真实用户行为。
我们集成了 @testing-library/user-event,通过模拟 click -> type -> enter 的完整流程,让组件“以为”是真人在操作。
结语
前端自动化不仅仅是简单的 DOM 操作,更需要对框架原理有深入理解。 希望本文对你有所启发。
👉 官网地址:51bpms.com
也可以添加微信详细沟通