yucatio@システムエンジニア

趣味で作ったものいろいろ

Material-UIのDrawerを使用する(STEP 4 : Material-UIの導入 - React + Redux + Firebase チュートリアル)

★前回の記事

yucatio.hatenablog.com

Material-UIのDrawerを使用して、タスクのフィルタを行うボタンを右側に配置します。

ファイル名とコンポーネント名の変更

タスクのフィルタ用のボタンがフッターではなくなるので、Footer.jsのファイル名を変更します。また、Linkコンポーネントもより内容を表す名前に変更します。

  • src/components/todos/Footer.jssrc/components/todos/FilterNav.jsにリネームします。
  • src/components/todos/Link.jssrc/components/todos/FilterButton.jsにリネームします。
  • src/containers/todos/FilterLink.jssrc/containers/todos/FilterItem.jsにリネームします。

コンポーネント名を書き換えます。

src/components/todos/FilterNav.js({/* xxx */}のコメントは実行前に削除してください)

// import FilterLink from '../../containers/todos/FilterLink'  を削除
import FilterItem from '../../containers/todos/FilterItem'  // 追加

const FilterNav = () => (  {/* 変更 */}
  <p>
    Show:
    <FilterItem filter={VisibilityFilters.SHOW_ALL}>  {/* 変更 */}
      All
    </FilterItem>  {/* 変更 */}
    <FilterItem filter={VisibilityFilters.SHOW_ACTIVE}>  {/* 変更 */}
      Active
    </FilterItem>  {/* 変更 */}
    <FilterItem filter={VisibilityFilters.SHOW_COMPLETED}>  {/* 変更 */}
      Completed
    </FilterItem>  {/* 変更 */}
  </p>
)

export default FilterNav  // 変更

src/components/todos/FilterButton.js({/* xxx */}のコメントは実行前に削除してください)

const FilterButton = ({ active, children, onClick }) => (  {/* 変更 */}
  // 略
)

FilterButton.propTypes = {  // 変更
  // 略
}

export default FilterButton  // 変更

src/containers/todos/FilterItem.js

// import Link from '../../components/todos/Link'  を削除
import FilterButton from '../../components/todos/FilterButton'  // 追加

const FilterItem = connect( // 変更
  mapStateToProps,
  mapDispatchToProps
)(FilterButton) // 変更

export default FilterItem // 変更

src/components/todos/index.js

//import Footer from './Footer' を削除
import FilterNav from './FilterNav'

class TodoComponent extends React.Component {
  // 略
  render() {
    const {isOwnTodos, match: { params: {uid}}, classes} = this.props;
    return (
      <div className={classes.todoListRoot}>
        <Paper className={classes.todoListContent}>
          {/* 略 */}
          <FilterNav />  {/* FooterをFilterNavに変更 */}
        </Paper>
      </div>
    )
  }
}

変更後、エラーが出ていないことを確認してください。

Drawerの使用

画面右側にタスクのフィルタを行うボタンを配置します。

きちんと書くとすれば、画面の横幅に合わせて、Drawerを常時表示するかアクションがあった時のみ表示するかを切り替えるべきですが、今回は簡単のため、常時右側に表示します。 デフォルトではDrawerはAppbarよりも上に表示されますが、今回はAppbarよりも下に表示します。

Appbarよりも下に表示されるDrawerの導入

src/components/todos/index.js({/* xxx */}のコメントは実行前に削除してください)

const styles = theme => ({
  root: {  // 追加
    display: 'flex',  // #1
  },
  todoListRoot: {
    flexGrow: 1,  // #2
    padding: theme.spacing.unit * 3,
  },
  // 略
})

class TodoComponent extends React.Component {
  // 略
  render() {
    const {isOwnTodos, match: { params: {uid}}, classes} = this.props;
    return (
      <div className={classes.root}>  {/* 追加 */}
        <div className={classes.todoListRoot}>
          <Paper className={classes.todoListContent}>
            <Title isOwnTodos={isOwnTodos} uid={uid} />
            {isOwnTodos && <AddTodo uid={uid} />}
            <VisibleTodoList uid={uid} isOwnTodos={isOwnTodos} />
            {/* <FilterNav /> は下に移動 */}
          </Paper>
        </div>
        <FilterNav />  {/* ここに移動 */}
      </div>  {/* 追加 */}
    )
  }
}
  • display: 'flex’を使用して、タスク一覧とタスクフィルタを横に並べます(#1)。
  • flexGrow: 1を指定して、タスク一覧の幅をを可能な限り多く取ります(#2)。

src/components/todos/FilterNav.js({/* xxx */}のコメントは実行前に削除してください)

import PropTypes from 'prop-types'  // 追加
import { withStyles } from '@material-ui/core/styles'  // 追加
import Drawer from '@material-ui/core/Drawer'  // 追加

const drawerWidth = 240  // 追加

// stylesを追加
const styles = theme => ({
  drawer: {
    width: drawerWidth,
    flexShrink: 0,  // #1
  },
  drawerPaper: {
    width: drawerWidth,
  },
  toolbar: theme.mixins.toolbar,
})

const FilterNav = ({ classes }) => (  // classesを追加
  <Drawer variant="permanent" anchor="right"
                 className={classes.drawer} classes={{ paper: classes.drawerPaper, }}>  {/* #2 */}
    <div className={classes.toolbar} />  {/* #3 */}
    Show:
    <FilterItem filter={VisibilityFilters.SHOW_ALL}>
      All
    </FilterItem>
    {/* 略 */}
  </Drawer>  {/* 変更 */}
)

// propTypesを追加
FilterNav.propTypes = {
  classes: PropTypes.object.isRequired,
}

export default withStyles(styles)(FilterNav)  // 変更
  • flexShrink: 0を指定して、Drawerが縮まないようにしています(#1)。
  • Drawerでフィルタメニューを囲みます(#2)。variant="permanent"を指定することで常時表示し、anchor="right"で画面右側に表示します。
  • divを追加します(#3)。classes.toolbarを指定して、toolbarぶんの余白を設けます。

src/components/header/index.js

const styles = theme => ({
  appBar: {  // 追加
    zIndex: theme.zIndex.drawer + 1,  // #1
  },
  // 略
})

const Header = ({ classes }) => (
  <AppBar className={classes.appBar}>  {/* classNameを追加 */}
    {/* 略 */}
  </AppBar>
)
  • zIndexをdrawerより大きくすることで、AppbarをDrawarより前に表示します(#1)。

ここまでの実行結果です。画面右側にフィルタメニューが表示されました。

f:id:yucatio:20181213145240p:plain

フィルタメニューをListに変更する

reactのbuttonを使用している部分をMaterial-UIのListとListItemに変更します。

src/components/todos/FilterNav.js

import List from '@material-ui/core/List'  // 追加
import ListSubheader from '@material-ui/core/ListSubheader'  // 追加

const FilterNav = ({ classes }) => (
  <Drawer variant="permanent" anchor="right"
                 className={classes.drawer} classes={{ paper: classes.drawerPaper, }}>
    <div className={classes.toolbar} />
    <List subheader={<ListSubheader component="div">表示</ListSubheader>}>  {/* #1 */}
      <FilterLink filter={VisibilityFilters.SHOW_ALL}>
        全て  {/* 日本語に変更 */}
      </FilterLink>
      <FilterLink filter={VisibilityFilters.SHOW_ACTIVE}>
        未完了  {/* 日本語に変更 */}
      </FilterLink>
      <FilterLink filter={VisibilityFilters.SHOW_COMPLETED}>
        完了  {/* 日本語に変更 */}
      </FilterLink>
    </List>  {/* 追加 */}
  </Drawer>
)
  • Listコンポーネントでフィルタメニューを囲みます(#1)。subheaderでリストのヘッダを設定します。

src/components/todos/FilterButton.js({/* xxx */}のコメントは実行前に削除してください)

import ListItem from '@material-ui/core/ListItem'  // 追加
import ListItemIcon from '@material-ui/core/ListItemIcon'  // 追加
import ListItemText from '@material-ui/core/ListItemText'  // 追加
import Done from '@material-ui/icons/Done'  // 追加

const FilterButton = ({ active, children, onClick }) => (
  <ListItem button  // #1
    onClick={onClick}
    disabled={active}
    >
    {active &&
      <ListItemIcon>   {/* #2 */}
        <Done />
      </ListItemIcon>}
    <ListItemText inset primary={children} />   {/* #3 */}
  </ListItem>
)
  • buttonをListItemに変更し、buttonのインターフェースを設定します(#1)。styleは削除します。
  • activeがtrueの時は、Doneアイコン(チェックマークのアイコン)を表示します(#2)。
  • テキストはListItemText要素を使用します(#3)。insetでテキストの位置をそろえます。

実行結果です。 現在使用されているフィルタはdisabledかつ左側にチェックマークがつきました。

f:id:yucatio:20181213144722p:plain

以上でMaterial-UIのDrawerを使用してフィルタメニューを変更することができました。

参考

★次回の記事

yucatio.hatenablog.com

★目次

yucatio.hatenablog.com