React + Material-UI を勉強しています。今日は「ダイアログ」「モーダル」などと呼ばれる機能の使い方をまとめます。
React のチュートリアルは一通り終えていざ自分で作ろうとするとつまずくことがあるかと思います。なかでも Material-UI の公式ページは便利だけど理解し辛いなあと思うので「使い方」の点からまとめます。ちなみに Dialog ってのはこんな奴ですね。GIFはMaterial-UI のサンプルページです。
大雑把なプロセスは
- Dialog のデザインを決める
- Dialog を含むコンポーネントを作る SampleDialog
- SampleDialog を開くトリガーを作る
- state のリフトアップ
となります。
ダイアログのデザインを決める
Dialog を含むコンポーネントのデザインを決めます。直接 <Dialog />
に props を渡せるなら一手間省けますが、今回はひとまわりラッピングされたコンポーネントを想定します。
コンポーネントを作る
ダイアログとトリガーのコンポーネントを作ります。ここでは仮に SampleDialog, SampleCard と名付けます。トリガーのコンポーネントは Card にするつもりなので SampleCard と名付けました。 SampleCard のなかの Button をクリックしてダイアログを開くようにしたいと思います。
図のような構造になります。
SampleDialog を開くトリガーを作る
SampleDialog を開くトリガーを作ります。つまり、 SampleCard のなかに Button を配置します。
class SampleCard extends React.Component {
render() {
return (
<Card>
<CardContent>Lorem ipsum dolor sit amet</CardContent>
<CardActions>
<Button variant="contained" color="primary">
Open Dialog!
</Button>
</CardActions>
</Card>
);
}
}
state のリフトアップ
このセクションがいちばん大変ですね笑。
React では2つ以上のコンポーネントで状態のやりとりをするために共通の親コンポーネントを作り state を一元化するという手法を取ります。これを state のリフトアップと呼んでいます。今回の場合は SampleDialog と SampleCard の間で open という bool 値を共有する必要があります。それを仮に Parent と名付けます。 Parent の state に open を用意します。
ダイアログを開く
- SampleCard 内部の Button がクリックされる
- Parent の open が true になる
- SampleDialog の props.open が true になりダイアログが開く
というステップがあります。 では、1 から 2 を繋ぐにはどうすればいいのでしょうか?子コンポーネントから親コンポーネントの state をいじるのはできません。そのため、親コンポーネントから渡す props に親コンポーネントの state を変更するメソッドを渡します。たとえば、handleOpen
というメソッドを作ります。中身は this.setState({open: true})
です。つまり、 Parent の state を変更するメソッドです。そして、 constructor でメソッドを.bind(this)
しておきます(ここは説明不十分だと思います。後日追記する予定)。
そして、このメソッドを SampleCard に渡します。
Card の props にonClick: handleOpen
が入っていますね。これを Button への props に渡すことで 1 から 2 へのステップが実現します。
2から3へのステップは簡単です。Parent から SampleDialog に渡された props.open を<Dialog>
に渡します。これでダイアログを開けるようになりました。
ダイアログを閉じる
Dialog は Backdrop(ダイアログの背景、つまり本体より外側の部分)をクリックすると onClose
がコールバックされます。onClose
で Parent の open を false にすればダイアログも閉じられます。「ダイアログを開く」でやったのと同じように
- Parent で メソッド
handleClose
を定義する - Parent から SampleDialog へ props で
onClose={handleClose}
を渡す
というステップです。
わかりにくかった点
Material-UI のサンプルは Hooks を使ったコードです。それを知らずに読んでいると混乱してしまいました。「俺の知ってる React じゃないぞ???」となりました笑。
おわり
途中で力尽きたので、コードサンプルは載せていません。気が向けば書きます笑。
自分を含めた初心者のための備忘録として書いています。間違い、もっとよい方法などございましたらぜひ教えてください。
参考
https://material-ui.com/api/dialog/
Dialog の props を調べられます。いろいろカスタムできます。