著者は、 Creative Commons を選択して、 Write forDOnationsプログラムの一環として寄付を受け取りました。
序章
Web開発では、eventsはWebブラウザーで発生するアクションを表します。 イベントハンドラーを使用してイベントに応答することにより、マウスでのクリック、Webページのスクロール、タッチスクリーンのタッチなど、あらゆるユーザーアクションに応答する動的なJavaScriptアプリケーションを作成できます。もっと。
React アプリでは、イベントハンドラーを使用して、状態データを更新したり、 prop の変更をトリガーしたり、デフォルトのブラウザーアクションを防止したりできます。 これを行うために、Reactはネイティブのイベントインターフェースの代わりにSyntheticEvent
ラッパーを使用します。 SyntheticEvent
は、標準のブラウザーイベントを厳密にエミュレートしますが、さまざまなWebブラウザーに対してより一貫した動作を提供します。 Reactは、コンポーネントが Document Object Model(DOM)にマウントおよびアンマウントするときに、 Window イベントリスナーを安全に追加および削除するツールも提供し、[X197Xを制御できるようにします。 ]不適切に削除されたリスナーからのメモリリークを防止しながらのイベント。
このチュートリアルでは、Reactでイベントを処理する方法を学びます。 自己検証型の入力コンポーネントや入力フォームの有益なツールチップなど、ユーザーイベントを処理するいくつかのサンプルコンポーネントを作成します。 チュートリアル全体を通して、コンポーネントにイベントハンドラーを追加する方法、SyntheticEvent
から情報を取得する方法、およびWindow
イベントリスナーを追加および削除する方法を学習します。 このチュートリアルを終えると、さまざまなイベントハンドラーを操作して、Reactでサポートされているイベントのカタログを適用できるようになります。
前提条件
- Node.jsを実行する開発環境が必要になります。 このチュートリアルは、Node.jsバージョン10.22.0およびnpmバージョン6.14.6でテストされました。 これをmacOSまたはUbuntu18.04にインストールするには、Node.jsをインストールしてmacOSにローカル開発環境を作成する方法またはのPPAを使用したインストール]セクションの手順に従います。 Ubuntu18.04にNode.jsをインストールする方法。
- Create React App でセットアップされたReact開発環境で、不要なボイラープレートが削除されています。 これを設定するには、ステップ1 —Reactクラスコンポーネントの状態を管理する方法のチュートリアルの空のプロジェクトを作成します。 このチュートリアルでは、プロジェクト名として
events-tutorial
を使用します。 - また、JavaScriptとHTMLの基本的な知識も必要です。これは、HTMLシリーズでWebサイトを構築する方法およびJavaScriptでコーディングする方法にあります。 CSSの基本的な知識も役立ちます。これは、 Mozilla DeveloperNetworkで見つけることができます。
- Reactコンポーネント、
useState
フック、およびuseReducer
フックを使用します。これらは、チュートリアルReactおよびでカスタムコンポーネントを作成する方法で学習できます。 ]Reactコンポーネントのフックで状態を管理する方法。
ステップ1—SyntheticEvent
を使用してイベントデータを抽出する
このステップでは、<input>
HTML要素とonChange
イベントハンドラーを使用して検証コンポーネントを作成します。 このコンポーネントは、入力を受け入れて検証するか、コンテンツが特定のテキストパターンに準拠していることを確認します。 SyntheticEvent
ラッパーを使用して、イベントデータをコールバック関数に渡し、<input>
からのデータを使用してコンポーネントを更新します。 また、SyntheticEvent
からfunctions (preventDefault
など)を呼び出して、標準のブラウザーアクションを防止します。
Reactでは、イベントリスナーを追加する前に要素を選択する必要はありません。 代わりに、小道具を使用してJSXにイベントハンドラーを直接追加します。 React には、onClick
やonChange
などの一般的なイベントや、onWheel
などのあまり一般的でないイベントなど、でサポートされるイベントが多数あります。
ネイティブDOMoneventハンドラーとは異なり、ReactはSyntheticEvent
と呼ばれる特別なラッパーをネイティブブラウザーEvent
ではなくイベントハンドラーに渡します。 抽象化は、ブラウザー間の不整合を減らすのに役立ち、コンポーネントにイベントを操作するための標準インターフェースを提供します。 SyntheticEvent
のAPIは、ネイティブのEvent
に似ているため、ほとんどのタスクは同じ方法で実行されます。
これを実証するために、検証入力を行うことから始めます。 まず、FileNamer
というコンポーネントを作成します。 これは、ファイルに名前を付けるための入力を持つ<form>
要素になります。 入力を入力すると、コンポーネントの上にあるプレビューボックスが更新される情報が表示されます。 コンポーネントには、検証を実行するための送信ボタンも含まれますが、この例では、フォームは実際には何も送信しません。
まず、ディレクトリを作成します。
mkdir src/components/FileNamer
次に、テキストエディタでFileNamer.js
を開きます。
nano src/components/FileNamer/FileNamer.js
FileNamer.js
内に、ラッパー<div>
を作成してから、クラス名がpreview
のラッパー<div>
とラッパー内の<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>
で、テキストPreview
を含む<h2>
要素を追加しました。 これがプレビューボックスになります。 フォーム内に、Name:
をテキストとして持つ<label>
要素で囲まれた<input>
を追加しました。 次に、<form>
終了タグの直前に、Saveというbutton
を追加しました。
ファイルを保存して閉じます。
次に、App.js
を開きます。
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
を開きます。
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
を開きます。
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
に渡すデータのタイプによっても決まります。 たとえば、onKeyPress
イベントには、ユーザーが押したキーのcharCode
が含まれますが、onChange
には特定の文字コードは含まれませんが、完全な入力が含まれます。 。 これは、ユーザーが押したキーに応じて異なるアクションを実行する場合に重要です。
このチュートリアルでは、onChange
を使用して、最新のキーだけでなく、入力値全体をキャプチャします。 これにより、変更のたびに値を格納して連結する手間が省けます。
event
を引数として取る関数を作成し、onChange
プロパティを使用して<input>
要素に渡します。
イベント-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
はネイティブブラウザイベントではありません。 これはReactが提供するSyntheticEvent
であり、同じように扱われることがよくあります。 まれに、ネイティブイベントが必要な場合は、SyntheticEvent
のnativeEvent
属性を使用できます。
イベントができたので、イベントの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
がtrueの場合にメッセージを表示します。
イベント-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> ) }
このコードでは、alert
が最初にtrue
と等しく設定されている場合にのみ、&&
演算子を使用して新しい<div>
を表示しました。 <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)
を呼び出します。 コードの最後の部分で、onClick
を使用して<button>
要素にイベントハンドラーを追加しました。
ファイルを保存します。 以前と同様に、onMouseDown
を使用することもできますが、onClick
の方が一般的であるため、予期しない副作用を回避できます。 このフォームには送信アクションはありませんが、デフォルトのアクションを禁止することで、ページが再読み込みされないようにします。
これで、onChange
とonClick
の2つのイベントハンドラーを使用するフォームができました。 イベントハンドラーを使用して、ユーザーアクションをコンポーネントとアプリケーションに接続し、インタラクティブにします。 そうすることで、DOM要素にイベントを追加する方法と、同じアクションで発生するがSyntheticEvent
で異なる情報を提供するイベントがいくつかあることを学びました。 また、SyntheticEvent
から情報を抽出し、そのデータを状態に保存して他のコンポーネントを更新し、preventDefault
を使用してイベントを停止する方法も学びました。
次のステップでは、さまざまなユーザーアクションを処理するために、単一のDOM要素に複数のイベントを追加します。
ステップ2—同じ要素に複数のイベントハンドラーを追加する
1つのコンポーネントで複数のイベントが発生する場合があり、1つのコンポーネントでさまざまなイベントに接続できる必要があります。 たとえば、このステップでは、onFocus
およびonBlur
イベントハンドラーを使用して、コンポーネントに関するジャストインタイム情報をユーザーに提供します。 このステップを終えると、Reactでサポートされているさまざまなイベントと、それらをコンポーネントに追加する方法について詳しく知ることができます。
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>
要素に追加しました。 このイベントは、ユーザーがフィールドを選択したときにトリガーされます。 イベントハンドラーを追加した後、setAlert(true)
を呼び出してデータを表示する無名関数をonFocus
に渡しました。 この場合、SyntheticEvent
からの情報は必要ありません。 ユーザーが行動したときにのみイベントをトリガーする必要があります。 ReactはまだSyntheticEvent
を関数に送信していますが、現在の状況では、その中の情報を使用する必要はありません。
注: onClick
またはonMouseDown
でデータ表示をトリガーできますが、キーボードを使用してフォームフィールドにタブで移動するユーザーはアクセスできません。 この場合、onFocus
イベントは両方のケースを処理します。
ファイルを保存します。 これを行うと、ブラウザが更新され、ユーザーが入力をクリックするまで情報が非表示のままになります。
フィールドにフォーカスがあるときにユーザー情報が表示されるようになりましたが、データはコンポーネントの期間中存在します。 それをなくす方法はありません。 幸い、onBlur
と呼ばれる別のイベントがあり、ユーザーが入力を離れると発生します。 alert
をfalse
に設定する匿名関数を使用してonBlur
イベントハンドラーを追加します。 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
ディスプレイをinformation-wrapper
のclassName
を持つ新しい<div>
に移動します。 次に、information
のclassName
とsetAlert(true)
を呼び出すonClick
イベントを含む新しいボタンを追加します。
イベント-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> ) }
また、onFocus
およびonBlur
ハンドラーを<input>
要素から削除して、最後のステップからの動作を削除しました。
ファイルを保存して閉じます。 次に、FileNamer.css
を開きます。
nano src/components/FileNamer/FileNamer.css
popup
情報をボタンの上に完全に配置するために、スタイルを追加します。 次に、information
のクラスを持つ<button>
を、境界線のない青色に変更します。
イベント-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])
簡略化された例では、someProp
またはsomeOtherProp
が変更されるたびに、Reactは無名関数でコードを実行します。 配列内の項目は依存関係と呼ばれます。 このフックは、依存関係の変更をリッスンし、変更後に関数を実行します。
これで、useEffect
を使用して、alert
がtrue
の場合はいつでもイベントリスナーを追加し、alert
の場合はいつでも削除することで、グローバルイベントリスナーを安全に追加および削除するツールができました。 ]はfalse
です。
もう1つのステップがあります。 コンポーネントがアンマウントされると、useEffect
フックの内側から戻ってきた関数が実行されます。 このため、コンポーネントがアンマウントされたときにイベントリスナーを削除する関数も返す必要があります。
基本的な構造は次のようになります。
useEffect(() => { // run code when anything in the array changes return () => {} // run code when the component unmounts }, [someProp, someOtherProp])
useEffect
フックの形状がわかったので、アプリケーションで使用します。 FileNamer.js
を開きます:
nano src/components/FileNamer/FileNamer.js
内部で、useEffect
をインポートし、関数の後に配列に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(() => { }, [alert, setAlert]); ...
このコードでは、alert
とsetAlert
の両方を追加しました。 完了するために、Reactはすべての外部依存関係をuseEffect
関数に追加することをお勧めします。 setAlert
関数を呼び出すため、依存関係と見なすことができます。 setAlert
は最初のレンダリング後に変更されませんが、依存関係と見なされる可能性のあるものをすべて含めることをお勧めします。
次に、無名関数内に、setAlert(false)
を呼び出すhandleWindowClick
という新しい関数を作成します。
イベント-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]); ... }
次に、alert
がtrue
の場合にwindow.addEventListener('click', handleWindowClick)
を呼び出し、alert
の場合にwindow.removeEventListener('click', handleWindowClick)
を呼び出す条件付きを追加します。 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) 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
に別のイベントリスナーを追加して、メッセージも削除することです。 メソッドがclick
ではなくkeydown
になることを除いて、コードはほぼ同じです。
このステップでは、コンポーネント内にグローバルイベントリスナーを追加しました。 また、useEffect
フックを使用して、状態の変化に応じてイベントリスナーを適切に追加および削除する方法と、コンポーネントがアンマウントされたときにイベントリスナーをクリーンアップする方法についても学習しました。
結論
イベントハンドラーを使用すると、コンポーネントをユーザーアクションに合わせることができます。 これらは、アプリケーションに豊かなエクスペリエンスを提供し、アプリのインタラクティブな可能性を高めます。 また、ユーザーのアクションをキャプチャして応答する機能も提供します。
Reactのイベントハンドラーを使用すると、イベントコールバックをHTMLと統合しておくことができるため、アプリケーション全体で機能とデザインを共有できます。 ほとんどの場合、イベントハンドラをDOM要素に直接追加することに重点を置く必要がありますが、コンポーネントの外部でイベントをキャプチャする必要がある状況では、イベントリスナーを追加し、使用されなくなったときにクリーンアップして、メモリリークを防ぐことができます。パフォーマンスの高いアプリケーションを作成します。
Reactのチュートリアルをもっと見たい場合は、 Reactトピックページを確認するか、React.jsシリーズのコーディング方法ページに戻ってください。 JavaScriptでのイベントの詳細については、JavaScriptでのイベントの理解およびNode.jsでのイベントエミッターの使用のチュートリアルをご覧ください。