web-dev-qa-db-ja.com

ReactイベントハンドラーがdispatchEventで呼び出されないのはなぜですか?

Reactコンポーネント内の次の入力要素を検討してください。

<input onChange={() => console.log('onChange')} ... />

Reactコンポーネントをテストしている間、ユーザーが入力値を変更することをエミュレートしています:

input.value = newValue;
TestUtils.Simulate.change(input);

これにより、期待どおり'onChange'がログに記録されます。

ただし、'change'イベントが直接ディスパッチされる場合(私はjsdomを使用しています):

input.value = newValue;
input.dispatchEvent(new Event('change'));

onChangeハンドラーは呼び出されません。

どうして?

TestUtils.SimulateではなくdispatchEventを使用する動機は、TestUtils.Simulateがイベントバブリングをサポートしておらず、コンポーネントの動作がそれに依存しているためです。 TestUtils.Simulateなしでイベントをテストする方法があるかしら?

14
Misha Moroshko

ReactはSyntheticEventsを使用して独自のイベントシステムを使用します(ブラウザーの非互換性を防ぎ、reactでより多くのイベントを制御できます)。

TestUtilsを正しく使用すると、onChangeリスナーをトリガーするイベントが正しく作成されます。

一方、dispatchEvent関数は、「ネイティブ」ブラウザイベントを作成します。しかし、あなたが持っているイベントハンドラーはreactによって管理されているので、反応するだけで(badumts)SyntheticEventsに反応します。

あなたはここで反応イベントについて読むことができます: https://facebook.github.io/react/docs/events.html

6
Scarysize

ReactTestUtils.Simulateなしでそれを行う1つの方法:

var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://unpkg.com/react-trigger-change/dist/react-trigger-change.js';
document.head.appendChild(script);
input.value = value;
reactTriggerChange(input);

react-trigger-changeのソース を見て、必要なものを簡単に選択してください。スニペットの例:

if (nodeName === 'select' ||
    (nodeName === 'input' && type === 'file')) {
    // IE9-IE11, non-IE
    // Dispatch change.
    event = document.createEvent('HTMLEvents');
    event.initEvent('change', true, false);
    node.dispatchEvent(event);
  }
8
rofrol