[解決済み] useEffectフックにイベントを登録するには?
質問
Udemyの講座で、フックを使ってイベントを登録する方法について学んでいるのですが、講師が以下のようなコードを教えてくれました。
const [userText, setUserText] = useState('');
const handleUserKeyPress = event => {
const { key, keyCode } = event;
if (keyCode === 32 || (keyCode >= 65 && keyCode <= 90)) {
setUserText(`${userText}${key}`);
}
};
useEffect(() => {
window.addEventListener('keydown', handleUserKeyPress);
return () => {
window.removeEventListener('keydown', handleUserKeyPress);
};
});
return (
<div>
<h1>Feel free to type!</h1>
<blockquote>{userText}</blockquote>
</div>
);
これでうまくいくのですが、これが正しい方法だとは思えません。理由は、私が正しく理解していれば、再レンダリングのたびに、イベントは毎回登録と登録解除を繰り返し、それが正しい方法であるとは思えないからです。
そこで、私は少し修正し
useEffect
フックを以下のように変更しました。
useEffect(() => {
window.addEventListener('keydown', handleUserKeyPress);
return () => {
window.removeEventListener('keydown', handleUserKeyPress);
};
}, []);
第二引数に空の配列を指定することで、一度だけ効果を実行させることができます。
componentDidMount
. で、その結果を試してみると、キーを打つたびに加算されるのではなく、上書きされるのが不思議です。
私が期待していたのは
setUserText(
${userText}${key}
);
を使うと、新しく入力されたキーが現在の状態に追加され、新しい状態として設定されますが、その代わりに古い状態を忘れて新しい状態で書き換えられています。
再描画のたびにイベントの登録と解除を行うのは本当に正しい方法だったのでしょうか?
どのように解決するのですか?
このようなシナリオについて最善の方法は、イベント ハンドラで何を行っているかを確認することです。
もしあなたが単に
state
を設定するだけなら、以前の
state
を使用する場合、コールバックパターンを使用し、イベントリスナーを
初期
のマウント時にのみイベントリスナーを登録するのがよいでしょう。
を使用しない場合は コールバックパターン を使用しない場合、リスナーの参照とそのレキシカル スコープはイベント リスナーによって使用されますが、レンダリングごとに更新されたクロージャで新しい関数が作成されるため、ハンドラーで更新された状態にアクセスすることはできません。
const [userText, setUserText] = useState("");
const handleUserKeyPress = useCallback(event => {
const { key, keyCode } = event;
if(keyCode === 32 || (keyCode >= 65 && keyCode <= 90)){
setUserText(prevUserText => `${prevUserText}${key}`);
}
}, []);
useEffect(() => {
window.addEventListener("keydown", handleUserKeyPress);
return () => {
window.removeEventListener("keydown", handleUserKeyPress);
};
}, [handleUserKeyPress]);
return (
<div>
<h1>Feel free to type!</h1>
<blockquote>{userText}</blockquote>
</div>
);
関連
-
[解決済み] 配列から特定の項目を削除するにはどうすればよいですか?
-
[解決済み] jQueryで要素が非表示になっているかどうかを確認するには?
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] あるJavaScriptファイルを他のJavaScriptファイルにインクルードするにはどうすればよいですか?
-
[解決済み] GUID / UUIDの作成方法
-
[解決済み] jQueryでチェックボックスに "checked "を設定する
-
[解決済み】別のウェブページにリダイレクトするにはどうすればいいですか?
-
[解決済み】JavaScriptで文字列の出現箇所をすべて置換する方法
-
[解決済み] Javascriptで動的に命名されたメソッドを呼び出すにはどうすればよいですか?
-
[解決済み] Chrome拡張機能:popup.htmlを強制終了させる
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] useEffect React Hook使用時の依存性欠如の警告を修正する方法
-
[解決済み] AngularJSのエラーです。Cross Origin リクエストはプロトコルスキーム http, data, chrome-extension, https に対してのみサポートされています。
-
[解決済み] Google maps API V3 - 同一地点に複数のマーカーを設置する。
-
[解決済み] javascriptで2つの数値を連結する方法は?
-
[解決済み] javascript の関数から `undefined` と `null` のどちらを返すのが良いのでしょうか?
-
[解決済み] Javascript / jQueryでAndroid端末を検出する。
-
[解決済み] BlobからArrayBufferへ移行する方法
-
[解決済み] AJAX Mailchimp サインアップフォームの統合
-
[解決済み] JSHintの'+'前の改行不良の説明
-
[解決済み] V8 Javascript エンジンのスタンドアロン実行