ReactではBootstrapの代わりにMaterial-UIを使ってみる

[superAgentでRailsとReactをAPI連携しつつ、簡易的な表テーブルを作成する](http://qiita.com/Takkiii/items/6cee0eda4aabf29bac74)の続き。

前回はRailsとReactをAPI連携させて、表テーブルを作成するというところまでやりました。
前回の完成物がこちら。

![image](https://qiita-image-store.s3.amazonaws.com/0/59672/f8930b2e-643a-831f-c1f4-1b92370b0db8.png)

今回は「Reactビギナーズガイド」に沿って表テーブルの編集機能を作っていく予定でしたが、ダサすぎてモチベーションが上がらないので、先にデザイン部分をいい感じにしていきたいと思います。

## Bootstrap的なやつが使いたい
僕は普段Railsで「何か作ってみるか」みたいなときは大抵Bootstrapを突っ込んでいるのですが、Reactではどうすべきなのかなと思い調べてみたところ、参考になる記事がありました。

* [早く・それなりの UI を実現する React コンポーネントセット 16 選](http://qiita.com/kyrieleison/items/39ce30dd2d204791a9ea)

この記事によると、

* **React を前提とした React コンポーネントセット**
* **既存の CSS を移植した React コンポーネントセット**

という2パターンがあるらしいということが分かります。
さらに読み進めていくと前者の方が都合が良さそうなので、今回は[Material-UI](http://www.material-ui.com/#/)というコンポーネントライブラリを使っていきたいと思います。

![image](https://qiita-image-store.s3.amazonaws.com/0/59672/7ab7c11e-6886-7f1c-d035-75a3251cb6d8.png)

Material-UIについてざっと概要を知りたいという方は、以下の記事がGIFや画像付きで分かりやすいかと思います。

* [Material UIを使ってカッコいいUIのReactアプリケーションを作ってみた](http://blog.takanabe.tokyo/2015/12/11/1778/)
* [公式サイト Material-UI](http://www.material-ui.com/#/)
* [Gtihub Material-UI](https://github.com/callemall/material-ui)

## Material-UIのインストール

```shell-session
$ npm install --save material-ui
```

## コンポーネントにテーマをインポートする

公式サイトの[Usage](http://www.material-ui.com/#/get-started/usage)を読むと、Material-UIのコンポーネントを使用するためには、テーマをインポートする必要があることが分かります。

公式サイトに倣ってコードを追記していきます。

```books.js
import React from 'react'
import ReactDOM from 'react-dom'
import request from 'superagent'
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider' // 追記

class Books extends React.Component {
  constructor() {
    super()
    this.state = {
      books: [],
    }
  }

  componentWillMount() {
    this.getState()
  }

  getState() {
    request
      .get('/api/books/index')
      .end((error, res) => {
      if (!error && res.status === 200) {
        const json = JSON.parse(res.text)
        this.setState({
          books: json.books,
        })
      } else {
        console.log(error)
      }
    })
  }

  render() {
    const {books} = this.state
    const headers = books[0] != null ? Object.keys(books[0]) : []
    return (
      <MuiThemeProvider> // 追記
        <div>
          <h1>BookApp</h1>
          <table>
            <thead>
              <tr>
                {headers.map((header, index) => {
                  return (
                    <th key={index}>{header}</th>
                  )
                })}
              </tr>
            </thead>
            <tbody>
            {books.map((book, index) => {
              return (
                <tr key={index}>
                  {Object.values(book).map((row, index) => {
                    return (
                      <td key={index}>{row}</td>
                    )
                  })}
                </tr>
              )
            })}
          </tbody>
          </table>
        </div>
      </MuiThemeProvider> // 追記
    )
  }
}

ReactDOM.render(
  <Books />,
  document.getElementById("books")
)
```

`MuiThemeProvider`は単一の要素をPropsとして渡す必要があるようです。
[Usage](http://www.material-ui.com/#/get-started/usage)のようにコンポーネントを渡すか、今回のように`<div>...</div>`などでラップされた単一の要素を渡せば問題なさそうです。

## 表テーブルをMaterial-UIを使って書き換える

Material-UIを使用する準備が整ったので、実際に表テーブルのコードを書き換えていきます。

```books.js
import React from 'react'
import ReactDOM from 'react-dom'
import request from 'superagent'
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
// 以下追記
import {Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn} from 'material-ui/Table'

class Books extends React.Component {
  constructor() {
    super()
    this.state = {
      books: [],
    }
  }

  componentWillMount() {
    this.getState()
  }

  getState() {
    request
      .get('/api/books/index')
      .end((error, res) => {
      if (!error && res.status === 200) {
        const json = JSON.parse(res.text)
        this.setState({
          books: json.books,
        })
      } else {
        console.log(error)
      }
    })
  }

  render() {
    const {books} = this.state
    const headers = books[0] != null ? Object.keys(books[0]) : []
    return (
      <MuiThemeProvider>
        <div>
          <h1>BookApp</h1>
          // <table>, <thead>, <tbody>, <tr>, <th>, <td>を変更
          // 詳しくは (http://www.material-ui.com/#/components/table) を参照
          <Table>
            <TableHeader>
              <TableRow>
                {headers.map((header, index) => {
                  return (
                    <TableHeaderColumn key={index}>{header}</TableHeaderColumn>
                  )
                })}
              </TableRow>
            </TableHeader>
            <TableBody>
              {books.map((book, index) => {
                return (
                  <TableRow key={index}>
                    {Object.values(book).map((row, index) => {
                      return (
                        <TableRowColumn key={index}>{row}</TableRowColumn>
                      )
                    })}
                  </TableRow>
                )
              })}
            </TableBody>
          </Table>
          // ここまで変更
        </div>
      </MuiThemeProvider>
    )
  }
}

ReactDOM.render(
  <Books />,
  document.getElementById("books")
)
```

ここまでで以下のようなUIになりました。

![image](https://qiita-image-store.s3.amazonaws.com/0/59672/f029adcd-584a-37ee-a71f-537ebf9f6d74.png)

もう少し良い感じにしていきたいので、Material-UIの`<Card>`というコンポーネントを使ってみたいと思います。

```books.js
import React from 'react'
import ReactDOM from 'react-dom'
import request from 'superagent'
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
import {Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn} from 'material-ui/Table'
import {Card, CardHeader} from 'material-ui/Card' // 追記

class Books extends React.Component {
  constructor() {
    super()
    this.state = {
      books: [],
    }
  }

  componentWillMount() {
    this.getState()
  }

  getState() {
    request
      .get('/api/books/index')
      .end((error, res) => {
      if (!error && res.status === 200) {
        const json = JSON.parse(res.text)
        this.setState({
          books: json.books,
        })
      } else {
        console.log(error)
      }
    })
  }

  render() {
    const {books} = this.state
    const headers = books[0] != null ? Object.keys(books[0]) : []
    return (
      <MuiThemeProvider>
        <Card> // 変更
          <CardHeader title="BookApp" /> // 変更
          <Table>
            <TableHeader>
              <TableRow>
                {headers.map((header, index) => {
                  return (
                    <TableHeaderColumn key={index}>{header}</TableHeaderColumn>
                  )
                })}
              </TableRow>
            </TableHeader>
            <TableBody>
              {books.map((book, index) => {
                return (
                  <TableRow key={index}>
                    {Object.values(book).map((row, index) => {
                      return (
                        <TableRowColumn key={index}>{row}</TableRowColumn>
                      )
                    })}
                  </TableRow>
                )
              })}
            </TableBody>
          </Table>
        </Card> // 変更
      </MuiThemeProvider>
    )
  }
}

ReactDOM.render(
  <Books />,
  document.getElementById("books")
)
```

のっぺりしていた表テーブルがカードにすることで立体感がでました！

![image](https://qiita-image-store.s3.amazonaws.com/0/59672/4458b447-0f5d-e996-8c5d-1d507c78eafa.png)

## まとめ

Material-UIはQiitaでもいくつか記事があるし、ドキュメントもしっかりしているのでかなり使いやすいと思います！
そろそろReactビギナーズガイドに沿って進めていきたい...。