ReactへのMaterial-UI、react-routerの導入【初学者のReact✗Railsアプリ開発第3回】

#やったこと
Reactの初期画面の状態からMaterial-UIとreact-routerによるルーティングを実装する
#開発環境
[DockerでRuby on Rails + Reactを別々にアプリ作成する環境構築手順](https://qiita.com/dl10yr/items/b76969da1c2c33595a4a)
#実装手順
###各種モジュールのインストール
Materai-UI、react-router、react-reduxなどアプリ開発で使うモジュールをインストールします。
（今回使わないものも含みます）

```javascript:package.json
{
  "name": "app_name",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.3.2",
    "@testing-library/user-event": "^7.1.2",
    "@loadable/component": "^5.10.3",
    "@material-ui/core": "^4.6.1",
    "@material-ui/icons": "^4.5.1",
    "@material-ui/styles": "^4.6.0",
    "axios": "^0.19.0",
    "connected-react-router": "^6.6.0",
    "lodash": "^4.17.15",
    "material-table": "^1.54.2",
    "material-ui": "^0.20.2",
    "material-ui-flat-pagination": "^4.0.0",
    "normalize.css": "^8.0.1",
    "prop-types": "^15.7.2",
    "query-string": "^6.9.0",
    "react": "^16.12.0",
    "react-custom-scrollbars": "^4.2.1",
    "react-dom": "^16.12.0",
    "react-infinite-scroll-component": "^5.0.4",
    "react-redux": "^5.0.4",
    "react-router-dom": "^4.2.2",
    "react-router-redux": "^5.0.0-alpha.9",
    "react-scripts": "3.3.0",
    "react-share": "^3.0.1",
    "react-spring": "^8.0.27",
    "react-swipe-card-chsstm": "^0.1.5",
    "react-swipeable-views": "^0.13.3",
    "react-with-gesture": "^4.0.8",
    "recharts": "^2.0.0-beta.1",
    "redux": "^4.0.4",
    "redux-form": "^8.2.6",
    "redux-logger": "^3.0.6",
    "redux-thunk": "^2.3.0",
    "styled-components": "^4.4.1",
    "vec-la": "^1.5.0"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}
```
```
$ npm install
```
#Reactの仕組み
超ざっくりな理解としてはこんな感じですかね。
![スクリーンショット 2020-01-11 10.18.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367226/e4f0e658-e637-b32e-5ae5-e82bef2a2020.png)

* サイトとしてはpublic/index.htmlが表示される
* `<div id=”root”></div>`の部分がsrc/index.jsによりレンダリングされる
* `<App/>`はsrc/App.jsから出力されたもの

#react-router
Reactでルーティングを行うライブラリです。
ルーティングを一言でいうと、パスと出力したい内容を結ぶことです。
XXX.com/Homeにアクセスしたら、Home.jsの内容を表示する。
XXX.com/Infoにアクセスしたら、Info.jsの内容を表示する。みたいな...

#Material-UI
Googleが言っている「マテリアルデザイン」を簡単にReactに実装できるようにしたパッケージ
#今回作るもの
###/
![スクリーンショット 2020-01-12 6.19.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367226/740c4104-9e85-120f-cd87-49b44afd5346.png)
###/term
![スクリーンショット 2020-01-12 6.19.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367226/d62dded3-8806-b728-6acc-fbea2a3b1c38.png)
###/info
![スクリーンショット 2020-01-12 6.19.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367226/c7b43c87-cd82-62d6-51c9-e50b8cf9bdf6.png)

* /,/home,/infoでルーティングする
* Material-UIを導入し、スタイリングを行う


#src/index.js
```javascript:index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

import { MuiThemeProvider } from '@material-ui/core/styles';
import { theme } from './materialui/theme'
import { BrowserRouter as Router } from 'react-router-dom';

ReactDOM.render(
  <MuiThemeProvider theme={theme}>
    <Router>
      <App />
    </Router>
  </MuiThemeProvider>
  , document.getElementById('root'));
```
* MUIThemeProviderタグで囲むことで、MaterialUIを適用している。theme={theme}の記述は、./materialui/theme.jsに記載したテーマカラーのカスタムを適用している
* Routerタグで、Routingを実現している

###materiaiui/theme.js
```javascript:theme.js
import { createMuiTheme } from '@material-ui/core/styles'

export const theme = createMuiTheme({  // #1
  palette: {
    primary: {
      light: '#484848',
      main: '#212121',
      dark: '#000000',
      contrastText: '#ffffff',
    },
    secondary: {
      light: '#ffffff',
      main: '#ffffff',
      dark: '#ffffff',
      contrastText: '#000000',
    },
  },
})
```

#src/App.js
```javascript:App.js
import React, { Component } from 'react';
import './App.css';
import Home from './containers/Home';
import Term from './containers/Term';
import Info from './containers/Info';
import { Route, Switch } from 'react-router-dom'

class App extends Component {
  render() {
    return (
      <div className="App">
        <BrowserRouter>
          <Switch>
            <Route exact path="/" component={Home} />
            <Route path="/info" component={Info} />
            <Route path="/term" component={Term} />
          </Switch>
        </BrowserRouter>
      </div >
    );
  }
}

export default App;
```
* BrowserRouterタグとSwitchタグとRouterタグを使ってルーティングを実装。この方の解説めっちゃ分かりやすい。 -> https://qiita.com/kosuke0820/items/77addd20db9e6f7809fe
* Routeタグで、pathごとに、それぞれのコンポーネントに切り替えてくれる。
* exactつけると全体一致、つけないとpathで先頭一致。

#src/containers/Home.js
```javascript:Home.js
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';

const styles = theme => ({
  home: {
    backgroundColor: "red",
    width: "50%"
  },
});

class Home extends React.Component {
  render() {
    const { classes } = this.props;
    return (
      <div className={classes.home}>
        <p>未ログイン</p>
        <Button variant="contained" color="secondary">
          Twitterで登録・ログイン
        </Button>
      </div>
    )
  }
}

Home.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withStyles(styles, { withTheme: true })(Home);
```

* withStyles(styles, { withTheme: true })(Home); で 上部に記載のstylesを適用している。withStylesの書き方は古いみたい。react Hookへの移行を促しているから？？？ https://qiita.com/gumiTECH/items/9e0f3172b8f85e93cbbe
* stylesのhomeに記載のスタイルが`<div className={classes.home}>`タグに適用されている。
* styleの書き方がcssの書き方と微妙に異なる。ハイフンを使わずに大文字になっていたり。
* Home.propTypes = {
  classes: PropTypes.object.isRequired,
}; でちゃんとpropsの型チェックをしている。propsはコンポネートをカスタマイズできるようにするパラメータ。


#src/containers/Info.js
```javascript:Info.js
import React from 'react';

class Info extends React.Component {
  render() {
    return (
      <h1>Info</h1>
    )
  }
}

export default Info;
```
#src/containers/Term.js
```javascript:Term.js
import React from 'react';

class Term extends React.Component {
  render() {
    return (
      <h1>Term</h1>
    )
  }
}

export default Term;
```