React初心者のための Material-UI 【Dialogの使い方編】

React + Material-UI を勉強しています。今日は「ダイアログ」「モーダル」などと呼ばれる機能の使い方をまとめます。

React のチュートリアルは一通り終えていざ自分で作ろうとするとつまずくことがあるかと思います。なかでも Material-UI の公式ページは便利だけど理解し辛いなあと思うので「使い方」の点からまとめます。ちなみに Dialog ってのはこんな奴ですね。GIFはMaterial-UI のサンプルページです。

![2020-08-09 12.25.21.mov.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335949/82bf8935-4fb2-935c-ec52-ac7be35dd200.gif)


大雑把なプロセスは

- Dialog のデザインを決める
- Dialog を含むコンポーネントを作る SampleDialog
- SampleDialog を開くトリガーを作る
- state のリフトアップ

となります。

## ダイアログのデザインを決める

Dialog を含むコンポーネントのデザインを決めます。直接 ```<Dialog />``` に props を渡せるなら一手間省けますが、今回はひとまわりラッピングされたコンポーネントを想定します。

## コンポーネントを作る

ダイアログとトリガーのコンポーネントを作ります。ここでは仮に SampleDialog, SampleCard と名付けます。トリガーのコンポーネントは Card にするつもりなので SampleCard と名付けました。 SampleCard のなかの Button をクリックしてダイアログを開くようにしたいと思います。

図のような構造になります。

![trigger-dialog-Page-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335949/649fa2c0-7076-e586-74c0-4bd5300e46ee.png)

## SampleDialog を開くトリガーを作る

SampleDialog を開くトリガーを作ります。つまり、 SampleCard のなかに Button を配置します。

```react

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 では２つ以上のコンポーネントで状態のやりとりをするために共通の親コンポーネントを作り state を一元化するという手法を取ります。これを state のリフトアップと呼んでいます。今回の場合は SampleDialog と SampleCard の間で open という bool 値を共有する必要があります。それを仮に Parent と名付けます。 Parent の state に open を用意します。

![trigger-dialog-Copy of Page-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335949/b2c3aacd-c0e2-48e0-9cdf-46f39206b060.png)

### ダイアログを開く

1. SampleCard 内部の Button がクリックされる
2. Parent の open が true になる
3. SampleDialog の props.open が true になりダイアログが開く

というステップがあります。 では、1 から 2 を繋ぐにはどうすればいいのでしょうか？子コンポーネントから親コンポーネントの state をいじるのはできません。そのため、親コンポーネントから渡す props に親コンポーネントの state を変更するメソッドを渡します。たとえば、``` handleOpen ``` というメソッドを作ります。中身は ```this.setState({open: true})``` です。つまり、 Parent の state を変更するメソッドです。そして、 constructor でメソッドを```.bind(this)```しておきます（ここは説明不十分だと思います。後日追記する予定）。

![trigger-dialog-Copy of Copy of Page-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335949/5ef934b8-0643-df44-b8df-0ab3a48f16bf.png)
そして、このメソッドを SampleCard に渡します。
![trigger-dialog-Copy of Copy of Copy of Page-4-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335949/0aeecf76-6c80-21ca-a5fc-ffb995808b72.png)
Card の props に``` onClick: handleOpen ``` が入っていますね。これを Button への props に渡すことで 1 から 2 へのステップが実現します。
![trigger-dialog-Copy of Page-8-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335949/bab97a7f-d3e3-5214-2356-c34173136f6c.png)

２から３へのステップは簡単です。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 を調べられます。いろいろカスタムできます。