著者は、 Creative Commons を選択して、 Write forDOnationsプログラムの一環として寄付を受け取りました。

序章

Web開発では、eventsはWebブラウザーで発生するアクションを表します。 イベントハンドラーを使用してイベントに応答することにより、マウスでのクリック、Webページのスクロール、タッチスクリーンのタッチなど、あらゆるユーザーアクションに応答する動的なJavaScriptアプリケーションを作成できます。もっと。

React アプリでは、イベントハンドラーを使用して、状態データを更新したり、 prop の変更をトリガーしたり、デフォルトのブラウザーアクションを防止したりできます。 これを行うために、Reactは SyntheticEvent ネイティブイベントインターフェイスの代わりにラッパー。 SyntheticEvent 標準のブラウザイベントを厳密にエミュレートしますが、さまざまなWebブラウザに対してより一貫した動作を提供します。 Reactは、コンポーネントが Document Object Model(DOM)にマウントおよびアンマウントするときに、 Window イベントリスナーを安全に追加および削除するためのツールも提供し、制御を可能にします。 Window メモリリークが不適切に削除されたリスナーからのイベントを防止します。

このチュートリアルでは、Reactでイベントを処理する方法を学びます。 自己検証型の入力コンポーネントや入力フォームの有益なツールチップなど、ユーザーイベントを処理するいくつかのサンプルコンポーネントを作成します。 チュートリアル全体を通して、コンポーネントにイベントハンドラーを追加し、から情報を取得する方法を学習します。 SyntheticEvent、および追加と削除 Window イベントリスナー。 このチュートリアルを終えると、さまざまなイベントハンドラーを操作して、Reactでサポートされているイベントのカタログを適用できるようになります。

前提条件

ステップ1—でイベントデータを抽出する SyntheticEvent

このステップでは、を使用して検証コンポーネントを作成します <input> HTML要素と onChange イベントハンドラ。 このコンポーネントは、入力を受け入れて検証するか、コンテンツが特定のテキストパターンに準拠していることを確認します。 を使用します SyntheticEvent イベントデータをコールバック関数に渡し、からのデータを使用してコンポーネントを更新するラッパー <input>. また、から関数を呼び出します SyntheticEvent、 そのような preventDefault 標準のブラウザアクションを防ぐため。

Reactでは、イベントリスナーを追加する前に要素を選択する必要はありません。 代わりに、小道具を使用してJSXにイベントハンドラーを直接追加します。 React には、でサポートされているイベントが多数あります。これには、次のような一般的なイベントが含まれます。 onClick また onChange となどのあまり一般的ではないイベント onWheel.

ネイティブDOMoneventハンドラーとは異なり、Reactはと呼ばれる特別なラッパーを渡します SyntheticEvent ネイティブブラウザではなくイベントハンドラに Event. 抽象化は、ブラウザー間の不整合を減らすのに役立ち、コンポーネントにイベントを操作するための標準インターフェースを提供します。 のAPI SyntheticEvent ネイティブに似ています Event、したがって、ほとんどのタスクは同じ方法で実行されます。

これを実証するために、検証入力を行うことから始めます。 まず、というコンポーネントを作成します FileNamer. これは <form> ファイルに名前を付けるための入力を持つ要素。 入力を入力すると、コンポーネントの上にあるプレビューボックスが更新される情報が表示されます。 コンポーネントには、検証を実行するための送信ボタンも含まれますが、この例では、フォームは実際には何も送信しません。

まず、ディレクトリを作成します。

  1. mkdir src/components/FileNamer

次に開きます FileNamer.js テキストエディタで:

  1. nano src/components/FileNamer/FileNamer.js

中身 FileNamer.js、ラッパーを作成します <div>、次に別の <div> クラス名は preview<form> 次のコード行を記述して、ラッパー内の要素を作成します。

イベント-tutorial/src / components / FileNamer / FileNamer.js
import React from 'react';

export default function FileNamer() {
  return(
    <div className="wrapper">
      <div className="preview">
      </div>
      <form>
      </form>
    </div>
  )
}

次に、プレビューボックスに表示する名前の入力要素と保存ボタンを追加します。 次の強調表示された行を追加します。

イベント-tutorial/src / components / FileNamer / FileNamer.js
import React from 'react';

export default function FileNamer() {
  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview:</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input name="name" />
        </label>
        <div>
          <button>Save</button>
        </div>
      </form>
    </div>
  )
}

の中に preview <div>、追加しました <h2> テキスト付きの要素 Preview. これがプレビューボックスになります。 フォーム内に、 <input> に囲まれています <label> 要素と Name: そのテキストとして。 次に、を追加しました button クロージングの直前にSaveと呼ばれます <form> 鬼ごっこ。

ファイルを保存して閉じます。

次に、開く App.js:

  1. nano src/components/App/App.js

輸入 FileNamer、次に内部でレンダリングします App 次の強調表示された行を追加して機能します。

イベント-tutorial/src / components / App / App.js
import React from 'react';
import FileNamer from '../FileNamer/FileNamer';

function App() {
    return <FileNamer />
}

export default App;

ファイルを保存して閉じます。 これを行うと、ブラウザが更新され、コンポーネントが表示されます。

次に、セクションを定義し、要素にパディングとマージンを追加するために、いくつかの軽いスタイルを追加します。

開ける FileNamer.css テキストエディタで:

  1. nano src/components/FileNamer/FileNamer.css

与える .preview 灰色の境界線とパディングを分類してから、 .wrapper 少量のパディングを分類します。 flexとを使用して列に項目を表示します flex-direction、すべてのテキストを左揃えにします。 最後に、境界線を削除して黒い境界線を追加することにより、デフォルトのボタンスタイルを削除します。

イベント-tutorial/src / components / FileNamer / FileNamer.css
.preview {
    border: 1px darkgray solid;
    padding: 10px;
}

.wrapper {
    display: flex;
    flex-direction: column;
    padding: 20px;
    text-align: left;
}

.wrapper button {
    background: none;
    border: 1px black solid;
    margin-top: 10px;
}

ファイルを保存して閉じます。 次に開きます FileNamer.js:

  1. nano src/components/FileNamer/FileNamer.js

スタイルをインポートして、コンポーネントに適用します。

イベント-tutorial/src / components / FileNamer / FileNamer.js
import React from 'react';
import './FileNamer.css';

export default function FileNamer() {
  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview:</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input name="name" />
        </label>
        <div>
          <button>Save</button>
        </div>
      </form>
    </div>
  )
}

ファイルを保存します。 これを行うと、ブラウザが更新され、コンポーネントに新しいスタイルが追加されていることがわかります。

基本的なコンポーネントができたので、イベントハンドラーをに追加できます。 <input> エレメント。 ただし、最初に、入力フィールドにデータを保存する場所が必要になります。 useState Hook を追加して、入力を保持します。

イベント-tutorial/src / components / FileNamer / FileNamer.js
import React, { useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
  const [name, setName] = useState('');
  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview: {name}.js</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input name="name" />
        </label>
        <div>
          <button>Save</button>
        </div>
      </form>
    </div>
  )
}

このコードでは、構造を解除しました useState 変数に name 入力と呼び出される関数を保持します setName データを更新します。 次に、 name プレビューセクションに続いて .js ユーザーがファイルに名前を付けているかのように、拡張子。

入力データを保存できるようになったので、イベントハンドラーをに追加できます。 <input> 成分。 多くの場合、特定のタスクに使用できるいくつかの異なるイベントハンドラーがあります。 この場合、アプリはユーザーが要素に入力したデータをキャプチャする必要があります。 この状況で最も一般的なハンドラーは onChange、コンポーネントが変更されるたびに起動します。 ただし、キーボードイベントなどを使用することもできます。 onKeyDown, onKeyPress、 と onKeyUp. 違いは主に、イベントが発生したときと情報が SyntheticEvent 物体。 例えば、 onBlur、要素の焦点が合わなくなったときのイベントが前に発生します onClick. 別のイベントが発生する前にユーザー情報を処理する場合は、以前のイベントを選択できます。

イベントの選択は、渡すデータのタイプによっても決まります。 SyntheticEvent. The onKeyPress たとえば、イベントには charCode ユーザーが押したキーの onChange 特定の文字コードは含まれませんが、完全な入力が含まれます。 これは、ユーザーが押したキーに応じて異なるアクションを実行する場合に重要です。

このチュートリアルでは、 onChange 最新のキーだけでなく、入力値全体をキャプチャします。 これにより、変更のたびに値を格納して連結する手間が省けます。

を取る関数を作成します event 引数として、それをに渡します <input> を使用する要素 onChange 小道具:

イベント-tutorial/src / components / FileNamer / FileNamer.js
import React, { useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
  const [name, setName] = useState('');
  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview: {name}.js</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input name="name" onChange={event => {}}/>
        </label>
        <div>
          <button>Save</button>
        </div>
      </form>
    </div>
  )
}

前述のように、 event これはネイティブブラウザイベントではありません。 それは SyntheticEvent 多くの場合同じように扱われるReactによって提供されます。 まれに、ネイティブイベントが必要な場合は、 nativeEvent の属性 SyntheticEvent.

イベントができたので、現在の値を target.value イベントのプロパティ。 値をに渡す setName プレビューを更新するには:

イベント-tutorial/src / components / FileNamer / FileNamer.js
import React, { useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
  const [name, setName] = useState('');
  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview: {name}.js</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input
           autoComplete="off"
           name="name"
           onChange={event => setName(event.target.value) }
         />
        </label>
        <div>
          <button>Save</button>
        </div>
      </form>
    </div>
  )
}

さらに、属性autoCompleteをに設定します "off" ブラウザの提案をオフにします。

ファイルを保存します。 これを行うと、ページがリロードされ、入力すると <input> プレビューに更新が表示されます。

注:を使用して入力の名前にアクセスすることもできます event.target.name. これは、複数の入力で同じイベントハンドラーを使用している場合に役立ちます。これは、 name 自動的に一致します name コンポーネントの属性。

この時点で、作業中のイベントハンドラーがあります。 ユーザー情報を取得して状態に保存し、データで別のコンポーネントを更新しています。 ただし、イベントから情報を取得するだけでなく、フォームの送信を防止したり、キー押下アクションを防止したりする場合など、イベントを停止する必要がある場合があります。

イベントを停止するには、 preventDefault イベントのアクション。 これにより、ブラウザはデフォルトの動作を実行できなくなります。

の場合 FileNamer コンポーネントには、アプリが禁止するファイルを選択するプロセスを中断する可能性のある特定の文字があります。 たとえば、ユーザーに追加してほしくない場合 * ワイルドカード文字と競合するため、ファイル名に変更します。ワイルドカード文字は、別のファイルセットを参照していると解釈される可能性があります。 ユーザーがフォームを送信する前に、無効な文字がないことを確認する必要があります。 無効な文字がある場合は、ブラウザによるフォームの送信を停止し、ユーザーへのメッセージを表示します。

まず、生成するフックを作成します alert booleanおよび setAlert 関数。 次に、 <div> メッセージを表示するには alert 本当です:

イベント-tutorial/src / components / FileNamer / FileNamer.js
import React, { useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
  const [name, setName] = useState('');
  const [alert, setAlert] = useState(false);

  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview: {name}.js</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input
            autoComplete="off"
            name="name"
            onChange={event => setName(event.target.value) }
          />
        </label>
        {alert && <div> Forbidden Character: *</div>}
        <div>
          <button>Save</button>
        </div>
      </form>
    </div>
  )
}

このコードでは、 && 新しいものだけを表示する演算子 <div> もしも alert に等しく設定されます true 最初。 のメッセージ <div> ユーザーに次のように伝えます * 入力に文字を使用することはできません。

次に、という関数を作成します validate. 正規表現.testメソッドを使用して、文字列に *. その場合、フォームの送信を防ぐことができます。

イベント-tutorial/src / components / FileNamer / FileNamer.js
import React, { useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
  const [name, setName] = useState('');
  const [alert, setAlert] = useState(false);
  const validate = event => {
    if(/\*/.test(name)) {
      event.preventDefault();
      setAlert(true);
      return;
    }
      setAlert(false);
 };

  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview: {name}.js</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input
            autoComplete="off"
            name="name"
            onChange={event => setName(event.target.value) }
          />
        </label>
        {alert && <div> Forbidden Character: *</div>}
        <div>
          <button onClick={validate}>Save</button>
        </div>
      </form>
    </div>
  )
}

いつ validate 関数が呼び出され、テストが返されます true、使用します event.preventDefault その後、電話 setAlert(true). それ以外の場合は、 setAlert(false). コードの最後の部分で、イベントハンドラーをに追加しました <button> 要素と onClick.

ファイルを保存します。 以前のように、あなたも使用することができます onMouseDown、 しかし onClick より一般的であるため、予期しない副作用を回避できます。 このフォームには送信アクションはありませんが、デフォルトのアクションを禁止することで、ページが再読み込みされないようにします。

これで、2つのイベントハンドラーを使用するフォームができました。 onChangeonClick. イベントハンドラーを使用して、ユーザーアクションをコンポーネントとアプリケーションに接続し、インタラクティブにします。 そうすることで、DOM要素にイベントを追加する方法と、同じアクションで発生するが、 SyntheticEvent. また、から情報を抽出する方法も学びました SyntheticEvent、そのデータを状態に保存して他のコンポーネントを更新し、を使用してイベントを停止します preventDefault.

次のステップでは、さまざまなユーザーアクションを処理するために、単一のDOM要素に複数のイベントを追加します。

ステップ2—同じ要素に複数のイベントハンドラーを追加する

1つのコンポーネントで複数のイベントが発生する場合があり、1つのコンポーネントでさまざまなイベントに接続できる必要があります。 たとえば、このステップでは、 onFocusonBlur コンポーネントに関するジャストインタイム情報をユーザーに提供するイベントハンドラー。 このステップを終えると、Reactでサポートされているさまざまなイベントと、それらをコンポーネントに追加する方法について詳しく知ることができます。

The validate 関数は、フォームが不正なデータを送信するのを防ぐのに役立ちますが、ユーザーエクスペリエンスにはあまり役立ちません。ユーザーは、フォーム全体に入力した後にのみ、有効な文字に関する情報を受け取ります。 複数のフィールドがある場合、最後のステップまでユーザーにフィードバックは提供されません。 このコンポーネントをよりユーザーフレンドリーにするために、ユーザーがフィールドに入力するときに許可されている文字と許可されていない文字を表示して、 onFocus イベントハンドラ。

まず、更新します alert <div> 許可される文字に関する情報を含めるため。 ユーザーに英数字が許可されていることと、 * 許可されていません:

イベント-tutorial/src / components / FileNamer / FileNamer.js
import React, { useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
...
  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview: {name}.js</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input
            autocomplete="off"
            name="name"
            onChange={event => setName(event.target.value) }
          />
        </label>
        {alert &&
         <div>
           <span role="img" aria-label="allowed"></span> Alphanumeric Characters
           <br />
           <span role="img" aria-label="not allowed">⛔️</span> *
         </div>
       }
        <div>
          <button onClick={validate}>Save</button>
        </div>
      </form>
    </div>
  )
}

このコードでは、 Accessible Rich Internet Applications(ARIA)標準を使用して、コンポーネントをスクリーンリーダーでよりアクセスしやすくしました。

次に、別のイベントハンドラーをに追加します <input> エレメント。 入力をクリックまたはタブで入力してコンポーネントをアクティブ化すると、許可されている文字と許可されていない文字についてユーザーに警告します。 次の強調表示された行を追加します。

イベント-tutorial/src / components / FileNamer / FileNamer.js
import React, { useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
...
  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview: {name}.js</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input
            autocomplete="off"
            name="name"
            onChange={event => setName(event.target.value) }
            onFocus={() => setAlert(true)}
          />
        </label>
        {alert &&
          <div>
            <span role="img" aria-label="allowed"></span> Alphanumeric Characters
            <br />
            <span role="img" aria-label="not allowed">⛔️</span> *
          </div>
        }
        <div>
          <button onClick={validate}>Save</button>
        </div>
      </form>
    </div>
  )
}

追加しました onFocus イベントハンドラー <input> エレメント。 このイベントは、ユーザーがフィールドを選択したときにトリガーされます。 イベントハンドラーを追加した後、匿名関数をに渡しました onFocus それは setAlert(true) データを表示します。 この場合、からの情報は必要ありません。 SyntheticEvent; ユーザーが行動したときにのみイベントをトリガーする必要があります。 Reactはまだ送信しています SyntheticEvent 関数に追加しますが、現在の状況では、関数内の情報を使用する必要はありません。

注:でデータ表示をトリガーできます onClick あるいは onMouseDown、ただし、キーボードを使用してフォームフィールドにタブで移動するユーザーはアクセスできません。 この場合、 onFocus イベントは両方のケースを処理します。

ファイルを保存します。 これを行うと、ブラウザが更新され、ユーザーが入力をクリックするまで情報が非表示のままになります。

フィールドにフォーカスがあるときにユーザー情報が表示されるようになりましたが、データはコンポーネントの期間中存在します。 それをなくす方法はありません。 幸いなことに、という別のイベントがあります onBlur これは、ユーザーが入力を離れたときに発生します。 追加します onBlur を設定する匿名関数を持つイベントハンドラー alertfalse. お気に入り onFocus、これは、ユーザーがクリックしたとき、またはユーザーがタブで移動したときの両方で機能します。

イベント-tutorial/src / components / FileNamer / FileNamer.js
import React, { useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
...
  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview: {name}.js</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input
            autocomplete="off"
            name="name"
            onBlur={() => setAlert(false)}
            onChange={event => setName(event.target.value) }
            onFocus={() => setAlert(true)}
          />
        </label>
        {alert &&
          <div>
            <span role="img" aria-label="allowed"></span> Alphanumeric Characters
            <br />
            <span role="img" aria-label="not allowed">⛔️</span> *
          </div>
        }
        <div>
          <button onClick={validate}>Save</button>
        </div>
      </form>
    </div>
  )
}

ファイルを保存します。 これを行うと、ブラウザが更新され、ユーザーが要素をクリックすると情報が表示され、ユーザーがクリックすると情報が消えます。

要素に必要な数のイベントハンドラーを追加できます。 必要なイベントのアイデアはあるが名前がわからない場合は、サポートされているイベントをスクロールすると、必要なものが見つかる可能性があります。

このステップでは、単一のDOM要素に複数のイベントハンドラーを追加しました。 さまざまなイベントハンドラーが、クリックとタブの両方などの幅広いイベント、または狭い範囲のイベントをどのように処理できるかを学びました。

次のステップでは、グローバルイベントリスナーをに追加します Window 直接のコンポーネントの外部で発生するイベントをキャプチャするオブジェクト。

ステップ3—ウィンドウイベントの追加

このステップでは、ユーザー情報をポップアップコンポーネントに配置します。このポップアップコンポーネントは、ユーザーが入力にフォーカスするとアクティブになり、ユーザーがページ上の他の場所をクリックすると閉じます。 この効果を実現するには、 useEffect Hook を使用して、グローバルイベントリスナーをWindowオブジェクトに追加します。 また、コンポーネントがアンマウントされたとき、メモリリークを防ぐため、アプリが必要以上のメモリを消費したときに、イベントリスナーを削除します。

この手順を完了すると、個々のコンポーネントでイベントリスナーを安全に追加および削除できるようになります。 また、使用方法も学びます useEffect コンポーネントがマウントおよびアンマウントされるときにアクションを実行するためのフック。

ほとんどの場合、JSXのDOM要素にイベントハンドラーを直接追加します。 これにより、コードに焦点が当てられ、コンポーネントが別のコンポーネントの動作を制御しているという混乱した状況を防ぐことができます。 Window 物体。 ただし、グローバルイベントリスナーを追加する必要がある場合があります。 たとえば、スクロールリスナーで新しいコンテンツをロードしたり、コンポーネントの外部でクリックイベントをキャプチャしたりできます。

このチュートリアルでは、ユーザーが特に要求した場合にのみ、入力に関する情報をユーザーに表示します。 情報を表示した後、ユーザーがコンポーネントの外部のページをクリックするたびに情報を非表示にする必要があります。

開始するには、 alert 新しいに表示 <div> とともに classNameinformation-wrapper. 次に、新しいボタンを追加します classNameinformationonClick 呼び出すイベント setAlert(true):

イベント-tutorial/src / components / FileNamer / FileNamer.js
import React, { useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
...
  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview: {name}.js</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input
            autocomplete="off"
            name="name"
            onChange={event => setName(event.target.value) }
          />
        </label>
        <div className="information-wrapper">
          <button
            className="information"
            onClick={() => setAlert(true)}
            type="button"
          >
            more information
          </button>
         {alert &&
           <div className="popup">
             <span role="img" aria-label="allowed"></span> Alphanumeric Characters
             <br />
             <span role="img" aria-label="not allowed">⛔️</span> *
           </div>
         }
        </div>
        <div>
          <button onClick={validate}>Save</button>
        </div>
      </form>
    </div>
  )
}

また、 onFocusonBlur からのハンドラー <input> 最後のステップから動作を削除する要素。

ファイルを保存して閉じます。 次に開きます FileNamer.css:

  1. nano src/components/FileNamer/FileNamer.css

絶対に配置するためにいくつかのスタイリングを追加します popup ボタンの上の情報。 次に、 <button> のクラスで information 境界線のない青になります。

イベント-tutorial/src / components / FileNamer / FileNamer.css

.information {
   font-size: .75em;
   color: blue;
   cursor: pointer;
}

.wrapper button.information {
    border: none;
}

.information-wrapper {
   position: relative;
}

.popup {
    position: absolute;
    background: white;
    border: 1px darkgray solid;
    padding: 10px;
    top: -70px;
    left: 0;
}

.preview {
    border: 1px darkgray solid;
    padding: 10px;
}

.wrapper {
    display: flex;
    flex-direction: column;
    padding: 20px;
    text-align: left;
}

.wrapper button {
    background: none;
    border: 1px black solid;
    margin-top: 10px;
}

ファイルを保存して閉じます。 これを行うと、ブラウザがリロードされ、クリックすると more information、コンポーネントに関する情報が表示されます。

これでポップアップをトリガーできますが、それをクリアする方法はありません。 この問題を修正するには、を呼び出すグローバルイベントリスナーを追加します setAlert(false) ポップアップの外側をクリックすると。

イベントリスナーは次のようになります。

window.addEventListener('click', () => setAlert(false))

ただし、コードでイベントリスナーを設定するときは注意が必要です。 たとえば、コンポーネントコードの先頭にイベントリスナーを追加することはできません。これは、何かが変更されるたびに、コンポーネントが再レンダリングされて新しいイベントリスナーが追加されるためです。 コンポーネントは何度も再レンダリングされる可能性が高いため、メモリを消費する未使用のイベントリスナーが多数作成されます。

これを解決するために、Reactには特別なフックがあります useEffect これは、特定のプロパティが変更された場合にのみ実行されます。 基本的な構造は次のとおりです。

useEffect(() => {
 // run code when anything in the array changes
}, [someProp, someOtherProp])

簡略化された例では、Reactは匿名関数でコードを実行します someProp また someOtherProp 変更します。 配列内の項目は依存関係と呼ばれます。 このフックは、依存関係の変更をリッスンし、変更後に関数を実行します。

これで、を使用してグローバルイベントリスナーを安全に追加および削除するためのツールができました。 useEffect いつでもイベントリスナーを追加する alerttrue いつでもそれを削除します alertfalse.

もう1つのステップがあります。 コンポーネントがアンマウントされると、内部から戻ってきた関数が実行されます useEffect 針。 このため、コンポーネントがアンマウントされたときにイベントリスナーを削除する関数も返す必要があります。

基本的な構造は次のようになります。

useEffect(() => {
 // run code when anything in the array changes
  return () => {} // run code when the component unmounts
}, [someProp, someOtherProp])

今、あなたはあなたの形を知っています useEffect フック、アプリケーションで使用します。 開く FileNamer.js:

  1. nano src/components/FileNamer/FileNamer.js

内部、インポート useEffect、次に依存関係のある空の無名関数を追加します alertsetAlert 関数の後の配列内:

イベント-tutorial/src / components / FileNamer / FileNamer.js
import React, { useEffect, useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
  const [name, setName] = useState('');
  const [alert, setAlert] = useState(false);

  useEffect(() => {
  }, [alert, setAlert]);
...

このコードでは、両方を追加しました alertsetAlert. 完了するために、Reactはすべての外部依存関係をに追加することをお勧めします useEffect 関数。 あなたが呼び出すので setAlert 関数、それは依存関係と見なすことができます。 setAlert 最初のレンダリング後は変更されませんが、依存関係と見なされる可能性のあるものをすべて含めることをお勧めします。

次に、無名関数内に、という新しい関数を作成します handleWindowClick それは setAlert(false):

イベント-tutorial/src / components / FileNamer / FileNamer.js
import React, { useEffect, useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
  const [name, setName] = useState('');
  const [alert, setAlert] = useState(false);

  useEffect(() => {
    const handleWindowClick = () => setAlert(false)
  }, [alert, setAlert]);
  ...
}

次に、条件付きを追加します。 window.addEventListener('click', handleWindowClick) いつ alerttrue と電話します window.removeEventListener('click', handleWindowClick) いつ alertfalse. これにより、ポップアップをトリガーするたびにイベントリスナーが追加され、ポップアップが閉じられるたびにイベントリスナーが削除されます。

イベント-tutorial/src / components / FileNamer / FileNamer.js
import React, { useEffect, useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
  const [name, setName] = useState('');
  const [alert, setAlert] = useState(false);

  useEffect(() => {
    const handleWindowClick = () => setAlert(false)
    if(alert) {
      window.addEventListener('click', handleWindowClick);
    } else {
      window.removeEventListener('click', handleWindowClick);
    }
  }, [alert, setAlert]);
  ...
}

最後に、イベントリスナーを削除する関数を返します。 繰り返しますが、これはコンポーネントがアンマウントされたときに実行されます。 ライブイベントリスナーがない場合もありますが、リスナーがまだ存在する状況では、クリーンアップする価値があります。

イベント-tutorial/src / components / FileNamer / FileNamer.js

import React, { useEffect, useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
  const [name, setName] = useState('');
  const [alert, setAlert] = useState(false);

  useEffect(() => {
    const handleWindowClick = () => setAlert(false)
    if(alert) {
      window.addEventListener('click', handleWindowClick);
    } else {
      window.removeEventListener('click', handleWindowClick)
    }
    return () => window.removeEventListener('click', handleWindowClick);
  }, [alert, setAlert]);
  ...
}

ファイルを保存します。 これを行うと、ブラウザが更新されます。 詳細情報ボタンをクリックすると、メッセージが表示されます。 開発ツールでグローバルイベントリスナーを見ると、 click リスナー:

コンポーネントの外側をクリックします。 メッセージが消え、グローバルクリックイベントリスナーが表示されなくなります。

君の useEffect フックは、ユーザーの操作に基づいてグローバルイベントリスナーを正常に追加および削除しました。 特定のDOM要素に関連付けられていませんでしたが、代わりにコンポーネントの状態の変更によってトリガーされました。

注:アクセシビリティの観点から、このコンポーネントは完全ではありません。 ユーザーがマウスを使用できない場合、コンポーネントの外側をクリックすることはできないため、ポップアップが開いたままになります。 解決策は、次のイベントリスナーを追加することです。 keydown メッセージも削除されます。 メソッドが次のようになることを除いて、コードはほぼ同じになります keydown それ以外の click.

このステップでは、コンポーネント内にグローバルイベントリスナーを追加しました。 また、使用方法も学びました useEffect 状態の変化に応じてイベントリスナーを適切に追加および削除し、コンポーネントがアンマウントされたときにイベントリスナーをクリーンアップする方法をフックします。

結論

イベントハンドラーを使用すると、コンポーネントをユーザーアクションに合わせることができます。 これらは、アプリケーションに豊かなエクスペリエンスを提供し、アプリのインタラクティブな可能性を高めます。 また、ユーザーのアクションをキャプチャして応答する機能も提供します。

Reactのイベントハンドラーを使用すると、イベントコールバックをHTMLと統合しておくことができるため、アプリケーション全体で機能とデザインを共有できます。 ほとんどの場合、イベントハンドラをDOM要素に直接追加することに重点を置く必要がありますが、コンポーネントの外部でイベントをキャプチャする必要がある状況では、イベントリスナーを追加し、使用されなくなったときにクリーンアップして、メモリリークを防ぐことができます。パフォーマンスの高いアプリケーションを作成します。

Reactのチュートリアルをもっと見たい場合は、 Reactトピックページを確認するか、React.jsシリーズのコーディング方法ページに戻ってください。 JavaScriptでのイベントの詳細については、JavaScriptでのイベントの理解およびNode.jsでのイベントエミッターの使用のチュートリアルをご覧ください。