質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
87.20%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

受付中

[React] useEffectとイベントハンドラの実行順序について

momo3159
hg7xka2

総合スコア1

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

1回答

0評価

0クリップ

191閲覧

投稿2022/06/18 04:18

質問事項

以下の2つの関数の間に,特定の実行順序(例: useEffectに渡した関数が先)はありますでしょうか?
もし存在しない場合,順序を制御する方法はありますでしょうか?

  • useEffectに渡した関数
  • イベントハンドラ

質問の背景

以下のコードは,refで参照するコンポーネントの外部をクリックするとコンポーネントを閉じる機能を提供するhooksになります.

useEffect内で,windowオブジェクトにclickイベントのイベントハンドラを登録しています.

javascript

import { useState, useEffect, useRef } from "react" export const useCloserWhenClickOutside = () => { const ref = useRef(null); const [state, setState] = useState(false); useEffect(() => { console.log('in useEffect') const clickOutsideModuleHandler = (e) => { console.log('event handler'); const moduleArea = ref.current; if (!state || moduleArea?.contains(e.target)) return; setState(false); }; window.addEventListener("click", clickOutsideModuleHandler); return () => { console.log('unmount') window.removeEventListener("click", clickOutsideModuleHandler); }; }, [state, ref]); return [state, setState, ref] }

以下のコードはaタグをクリックするとchildrenを表示し,children以外の部分をクリックするとchildrenを閉じるコンポーネントになっています.

javascript

import { useEffect, useState } from "react"; export const ButtonWithPopup = ({ value, children }) => { const [state, setState, ref] = useCloserWhenClickOutside(); const onClick = (e) => { console.log('open'); setState((prev) => !prev); }; return ( <div> {" "} <a onClick={onClick}> {value} </a> {state && <div ref={ref}>{children}</div>} </div> ); };

この時

  • react-datepickerというライブラリの DatePickerを子要素とした場合
  • そうでない場合

とで,custom hooks内でwindowに登録したclickイベントのハンドラと,useEffectに渡した関数の実行順序が異なる結果となりました.

javascript

import DatePicker from "react-datepicker"; export const App = () => { return ( <div> <ButtonWithPopup value="タイトル1"> <DatePicker /> </PopupButton> <PopupButton title="メンバー"> <div>hoge</div> </PopupButton> </div> ) }

実行結果

aタグをクリックし子要素を表示しようとした場合,コンソールにはどのように表示されているかの結果となります.

子要素がDatePickerの場合

1. open(aタグをクリックしたため) 2. unmount (stateがfalseからtrueに変わったため) 3. in useEffect 4. event handler(custom hooks内で登録したイベントハンドラ)

子要素がDatePickerでない場合

1. open 2. event handler(先に実行される) 3. unmount 4. in useEffect

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

momo3159

2022/06/18 08:18

clickOutsideModuleHandler内で, `console.log(ref.current, e.target, state, moduleArea?.contains(e.target));` を呼び出して値を確認してみました.結果としては`moduleArea?.contains(e.target)`は正しく動いていました. また,分かったこととしては以下の通りです. 子要素にDatePickerを使わない場合は, `refで参照しているDOM,クリックしたDOM,false, false` となりました.一方で,DatePickerを使った場合は, `refで参照しているDOM,クリックしたDOM,true, false`となりました. 従って,以下の手順になっているためクリックしても表示されないという形でした. 1. aタグをクリックして子要素を表示しようとする. 2. イベントハンドラの実行よりも先にクリーンアップ関数が呼ばれ,**stateがfalseの時のイベントハンドラが消去される** 3. useEffectの再実行が行われ,**stateがtrueの状態でイベントハンドラが登録される** 4. aタグをクリックした時のイベントに反応して,**クリック前に登録されていたイベントハンドラ(2で消去されたもの)**ではなく3の時のイベントハンドラが実行される

まだ回答がついていません

会員登録して回答してみよう

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
87.20%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。