如何使此输入组件反应正常?

时间:2019-08-14 17:14:56

标签: javascript reactjs dom-events react-hooks

这是一个反应输入组件:

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。我只想更改控制父组件中的值。

Here's a CodePen.

1 个答案:

答案 0 :(得分:1)

我通过模拟大写按钮上的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名称仍然可以正常工作。