Material-uiにはモーダル(ポップアップウインドウ)が用意されています。
表示だけならサンプルで動きますが実装するにあたって色々考えたのでメモ。
サンプル部分を見ると、トリガー(ボタン)とModalコンポーネントが同じように配置されてます。まずはApp.jsの設計を見ていつどこでModalが必要になるか考える。
Modalが共通の1つだけであればトリガーを子コンポーネントに渡してModalを使いまわしてもいいが、必要に応じてModalを配置したほうが混乱しにくい。
Modalは非表示の状態でもレンダリング処理が入る。
説明では表示領域はコンポーネント化して表示時のみ処理させろ書いている。
(表示部分が複雑な場合は自然とコンポーネント化するし、簡素な場合は大した負荷にならないからあまり気にする必要はない気がする)
なんにせよコンテント部分をコンポーネント化するならラッパーを作ってコンポーネントを渡してやれば汎用的に使える。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
import React, { Component } from 'react'; import PropTypes from 'prop-types'; import Modal from '@material-ui/core/Modal'; import { withStyles } from '@material-ui/core/styles'; const styles = theme => ({ paper: { position: 'absolute', width: theme.spacing.unit * 50, maxWidth: "100%", backgroundColor: theme.palette.background.paper, boxShadow: theme.shadows[5], padding: theme.spacing.unit * 4, outline: 'none', top: `50%`, left: `50%`, transform: `translate(-50%, -50%)`, }, }); class ModalWrapper extends Component { render() { console.log("modal render"); const { classes } = this.props; return ( <Modal id="Modal" aria-labelledby="simple-modal-title" aria-describedby="simple-modal-description" open={this.props.open} onClose={this.props.handleClose}> <div className={classes.paper}> {this.props.content} </div> </Modal> ); } } ModalWrapper.propTypes = { classes: PropTypes.object.isRequired, content: PropTypes.node.isRequired, open: PropTypes.bool.isRequired, handleClose: PropTypes.func.isRequired, }; export default withStyles(styles)(ModalWrapper); |
使う時は表示用コンポーネントを渡す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
import ModalContent from "./ModalContent"; ... state = { modalopen: false; }; handleClose = () => { this.setState({ modalopen: false }); }; render() { return( <ModalWrapper open={this.state.modalopen} handleClose={this.handleClose} content={<ModalContent/>} /> ); } |
シンプルになったような、複雑化しただけのような気もする。
リスト化した一覧をクリックして詳細を表示させるような用途では、渡すコンテントに値を渡して表示内容を都度変更するようにできる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
state = { modalopen: false, selectedItem: null, }; showXxx(item){ this.setState({ selectedItem: item }); } render() { return( <ModalWrapper ... content={<ModalContent item={this.selectedItem}/>} /> ); } |
Material-uiは色々用意されていますが実装するには慣れと理解が必要そう。
追記:スマホでモーダルの後ろがスクロールされる現象があったのでその対策。