React とダイアログ
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
◆ 開いたり閉じたりという動作が宣言型だと面倒
◆ 今の状態を管理して常にダイアログなどに渡す必要がある
◆ hook を使えば状態の管理を hook 内で行って dialog.open 関数の呼び出しで開ける
◆ 今の状態を管理して常にダイアログなどに渡す必要がある
◆ hook を使えば状態の管理を hook 内で行って dialog.open 関数の呼び出しで開ける
ダイアログに限るわけではありませんが React では宣言型というだけあって面倒な部分があります
何かを開いたり表示したりしたいといったとき DOM のメソッドなら open のようなメソッドを実行するだけです
閉じたときに結果が得られるなら返り値を待つだけです
alert のような同期的なものでなくても最近なら Promise と await でそれらしくできます
しかし React だと open のような変数に開いているかどうかという状態を保持して それをダイアログなどのコンポーネントに渡します
ダイアログ側では受け取った状態で開いてるか閉じてるかを制御します
また 閉じたときの結果の取得も コールバック関数も渡しておいて呼び出してもらうのを待つという作りになります
例えばこういうものです
onClose に渡した関数の引数が true なら OK ボタン false ならキャンセルや外部のクリック のような感じで判定します
この Dialog を使う例はこういう感じです
ボタンが押されたら msg に表示する文字列をセットして 文字列がセットされてるうちは ダイアログを開きます
閉じる操作が行われたら msg をクリアしてダイアログを閉じます
また 何を押して閉じたかを受け取り console.log で表示してます
これだけでも十分面倒なのに 画面にダイアログを開くボタンが複数あって ダイアログの種類も変わってくるとコードが長くて見づらくなってきます
Dialog コンポーネントをラップしたコンポーネントを作っても 結局外部から今開いてるかの状態を受け取らないとダメですし 閉じられたときにユーザの操作を返す必要があります
Dialog よりも使い方が簡単になりません
どうにかできないかなと考えてると hook を使えば良さそうに思いました
こういう hook を作っておきます
コンポーネント側はこうします
JSX 部分は開きたいときの onClick 設定と dialog.element の配置だけです
useDialog の引数でユーザ操作を受け取って処理する関数を指定します
ダイアログの表示状態は基本 hook の中で管理します
外からは開きたいときに dialog.open 関数を呼び出すだけになるので DOM のメソッドの方法に近くなりました
一応 onClick に設定しやすくするために dialog.openCb 関数も用意していて例ではこっちを使っています
何かを開いたり表示したりしたいといったとき DOM のメソッドなら open のようなメソッドを実行するだけです
alert("msg")
閉じたときに結果が得られるなら返り値を待つだけです
alert のような同期的なものでなくても最近なら Promise と await でそれらしくできます
const result = await openMyDialog("msg")
しかし React だと open のような変数に開いているかどうかという状態を保持して それをダイアログなどのコンポーネントに渡します
ダイアログ側では受け取った状態で開いてるか閉じてるかを制御します
また 閉じたときの結果の取得も コールバック関数も渡しておいて呼び出してもらうのを待つという作りになります
例えばこういうものです
<Dialog open={} message={} onClose={} />
onClose に渡した関数の引数が true なら OK ボタン false ならキャンセルや外部のクリック のような感じで判定します
この Dialog を使う例はこういう感じです
const [msg, setMsg] = useState(null)
const onDialogResult = (reason) => {
setMsg(null)
console.log(reason)
}
return (
<div>
<button onClick={() => setMsg("msg")}>open</button>
<Dialog open={!!msg} message={msg} onClose={onDialogResult} />
</div>
)
ボタンが押されたら msg に表示する文字列をセットして 文字列がセットされてるうちは ダイアログを開きます
閉じる操作が行われたら msg をクリアしてダイアログを閉じます
また 何を押して閉じたかを受け取り console.log で表示してます
これだけでも十分面倒なのに 画面にダイアログを開くボタンが複数あって ダイアログの種類も変わってくるとコードが長くて見づらくなってきます
Dialog コンポーネントをラップしたコンポーネントを作っても 結局外部から今開いてるかの状態を受け取らないとダメですし 閉じられたときにユーザの操作を返す必要があります
Dialog よりも使い方が簡単になりません
どうにかできないかなと考えてると hook を使えば良さそうに思いました
こういう hook を作っておきます
const useDialog = (cb, deps) => {
const [message, setMessage] = useState(null)
const element = useMemo(
() => (
<Dialog
open={!!message}
message={message}
onClose={(reason) => {setMessage(null), cb(reason)}}
/>`
),
[message, ...deps]
)
const openCb = msg => () => setMessage(msg)
const open = msg => setMessage(msg)
return { element, openCb, open }
}
コンポーネント側はこうします
const dialog = useDialog(reason => console.log(reason), [])
return (
<div>
<button onClick={dialog.openCb("msg")}>open</button>
{dialog.element}
</div>
)
JSX 部分は開きたいときの onClick 設定と dialog.element の配置だけです
useDialog の引数でユーザ操作を受け取って処理する関数を指定します
ダイアログの表示状態は基本 hook の中で管理します
外からは開きたいときに dialog.open 関数を呼び出すだけになるので DOM のメソッドの方法に近くなりました
一応 onClick に設定しやすくするために dialog.openCb 関数も用意していて例ではこっちを使っています