質問事項
以下の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
まだ回答がついていません
会員登録して回答してみよう