React 入門 (7) ~ TODOアプリを作る(2) ~ MATERIAL-UI の導入

UIがかっこいいとコーディングもノッてくるというもの。ということでMATERIAL-UIを入れてみる。

上記を参考にする。

インストール

まずは、必要なパッケージのインストール

$ npm install @material-ui/core

マイグレーション

次に、既存のコンポーネントをMaterial-UI に変更する。

  • buttonButton
  • ul を `List‘ に
  • liListItem & ListItemText

それぞれ変更していく。

ただ、そのまま実行すると onClick の型違いでエラーが発生するので、エラーの通り修正する。

  • HTMLLIElement を HTMLDivElement に変更
  • React.FormEvent を React.ChangeEvent に変更

それでもまだ問題があって、liListItemListItemText に分けたことで key 関係のエラーが再発する key 属性は ListItem に記述して、id属性は ListItemText に記述するとよい。

削除ボタンの変更

TODO を削除するボタンは今まで普通のボタンに - といった味気ないものだったので、これを機にゴミ箱アイコンに変更する。

List React component - Material-UI

ここらへんに良いサンプルがあるので参考にする。

新たにパッケージをインストールする。

$ npm install @material-ui/icons

以下のようにコードを変更する。これを button と置き換えるだけだ。簡単。

...
<ListItemSecondaryAction>
  <IconButton aria-label="Delete" onClick={this.on_click_for_del} id={String(i)}>
    <DeleteIcon />
  </IconButton>
</ListItemSecondaryAction>

マージンの設定

ここまでの実装で実行してみると、TODO追加ボタンとテキスト部分が近く感じる。いい感じにマージンを埋め込みたい。

Button React component - Material-UI

ここらへんのコードサンプルをみてみると、theme.spacing.unit という値を margin につけてやればいいようだが styles を作成するのに手間取った。

Material-UI のガイド > TypeScriptを試す1 - Qiita

この記事を見ると、コンポーネントを丸っとスタイル設定用の関数でくるんでやる必要があるようだった。今回は独自のprops インターフェースは必要なかったので、以下のように定義した。

ちなみに、以下のパッケージが必要になる。

$ npm install @material-ui/styles
// スタイル設定用の関数を定義
const decorate = withStyles((theme: Theme) => {
    return createStyles({
        button: {
            margin: theme.spacing.unit
        }
    });
});

// 定義部分を変更 decorate() 関数でクラスを丸っとラップ
const NumberList = decorate(
    class extends React.Component<WithStyles<'button'>, TodoState> {
// ...
    render() {
        const { classes } = this.props
        return (
            <div className="App">
            <div>
            // className に button 属性を指定することで、marginが効くようになる
            <Button color="primary" variant="contained" onClick={this.on_click} className={classes.button}>+</Button>
// ...

複数のコンポーネントのスタイルを設定する

上記の設定だと button のみが有効になる、root の要素に関してもスタイルを設定したい場合は、WithStyles<'button'> の部分を変更する必要がある。そのために、decorate関数で使っている withStyles をクラス定義のほうに移してくる必要がある。

// スタイル属性を定義。decorate関数にはしない。
const styles = (theme: Theme) => createStyles({
    root: {
        width: '100%',
        maxWidth: 360,
        backgroundColor: theme.palette.background.paper,
    },
    button: {
        margin: theme.spacing.unit
    }
});

// ラップする側でwithStyles()をすることで、WithStylesにstylesのタイプを指定できるようになる
const NumberList = withStyles(styles)(
    class extends React.Component<WithStyles<typeof styles>, TodoState> {

成果物

上記をすべて実装した場合、以下のようになる。

f:id:bamch0h:20190128233506g:plain
Material-UI

コード群は以下に挙げているので、興味があればみてほしい。

GitHub - bamchoh/react-study at 2019-01-28_add_material_ui

おわり。