这是一个反应输入组件:
function Input({ value, setValue }) {
return (
<div>
<input value={value} onChange={event => setValue(event.target.value)} />
<button onClick={() => setValue(value.toUpperCase())}>Capitalize</button>
</div>
);
}
它只是一个普通的输入组件和一个大写输入值的按钮。它应该由一些父组件控制:
function Parent() {
let [value, setValue] = useState("");
return <Input value={value} setValue={setValue} />;
}
这工作正常,但不是惯用语。为了可用作原版输入组件的"直接替换",它应该采用onChange
道具,而不是setValue
,相关的区别在于onChange
将合成事件作为参数,而setValue
采用字符串。(我希望大写按钮的存在对使用此Input
组件的开发人员来说是"不透明的"。
我试图通过在单击按钮时让输入元素触发更改事件来使其习惯化(请参阅下面的代码片段),但这不会导致onChange
执行。(我认为这是由于我不了解 react 合成事件系统的细节。我浏览了一堆关于这个主题的帖子,但无法让我找到的想法起作用。
function AnotherInput({ value, onChange }) {
let input = useRef();
let handleClick = () => {
input.current.value = value.toUpperCase();
var event = new Event("change" /* also tried "input" */, {
bubbles: true
});
input.current.dispatchEvent(event); // onChange doesn't fire!
};
return (
<div>
<input value={value} ref={input} onChange={onChange} />
<button onClick={handleClick}>Capitalize</button>
</div>
);
}
另外,我觉得我不应该在这里使用ref
,因为我不想直接修改 DOM;我只想更改控制父组件中的值。
这是一个代码笔。
我通过模拟大写按钮上的event Object
来使其工作。
父组件:
function Parent() {
let [value, setValue] = useState("");
return <Input value={value} onChange={(e) => setValue(e.target.value)} />;
}
输入组件:
编辑:我设法为输入组件提出了一个更优雅的解决方案:
function Input({ value, onChange: inheritedOnChange }) {
return (
<div>
<input value={value} onChange={inheritedOnChange} />
<button value={value.toUpperCase()} onClick={inheritedOnChange}>Capitalize</button>
</div>
);
}
请注意,我只是出于可读性目的将onChange
道具重命名为inheritedOnChange
。在解构时保留 onChange 名称应该仍然有效。