create-react-app + react-router + Material-UI で boilerplate

# 概要

create-react-app + react-router + Material-UI でアプリの雛形っぽいものを作ってみる。

下の react-router のサンプルを Material-UI で装飾するイメージ。
https://reacttraining.com/react-router/examples/basic


# 環境

- node 
v7.5.0

- npm 
4.1.2

- create-react-app
1.0.3

# 手順

アプリを生成して、必要な node-module をインストール。

```
create-react-app cra
cd cra
npm i --save react-tap-event-plugin    # おまじない
npm i --save react-router-dom
npm i --save material-ui
```

2017/2/15 各モジュールのバージョンは以下のとおり。

```package.json
{
  "name": "cra",
  "version": "0.1.0",
  "private": true,
  "devDependencies": {
    "react-scripts": "0.9.0"
  },
  "dependencies": {
    "material-ui": "^0.17.0",
    "react": "^15.4.2",
    "react-dom": "^15.4.2",
    "react-router-dom": "^4.0.0-beta.6",
    "react-tap-event-plugin": "^2.0.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}
```

public/index.html の body タグのデフォルトのマージンが Material-UI の AppBar と相性が悪いので、マージンを 0 にする。

```public/index.html

<!doctype html>
<html lang="en">

<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">

	<title>React App</title>
</head>

<body style='margin: 0'>
	<div id="root"></div>
</body>

</html>
```

MuiThemeProvider と Router の子要素は1つにしなくちゃいけないので、
MuiThemeProvider を index.js に Router を App.js に割り振ってみる。
逆でも大丈夫。 どっちかで両方やっても大丈夫。


```src/index.js
import React from 'react';
import ReactDOM from 'react-dom';

import getMuiTheme from 'material-ui/styles/getMuiTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';

import injectTapEventPlugin from 'react-tap-event-plugin'; // おまじない
injectTapEventPlugin(); // おまじない

import App from './App';


ReactDOM.render(
	<MuiThemeProvider muiTheme={getMuiTheme()}>
		<App />
	</MuiThemeProvider>
,	document.getElementById( 'root' )
);
```




```src/App.js
import React, { Component } from 'react';
import { AppBar, Drawer, List, ListItem } from 'material-ui';

import { BrowserRouter as Router, Route, Link } from 'react-router-dom';

const
Contact = () => <h2>----------------------------------Contact</h2>;

const
About = () => <h2>----------------------------------About</h2>;

const
Home = () => <h2>----------------------------------Home</h2>;

const
Topic = ( { match } ) => <h3>{match.params.topicId}</h3>;

const
Topics = ( { match } ) => <div>
	<h2>Topics</h2>
	<List>
		<ListItem containerElement={ <Link to={`${match.url}/rendering`} /> } primaryText='Rendering with React' />
		<ListItem containerElement={ <Link to={`${match.url}/components`} /> } primaryText='Components' />
		<ListItem containerElement={ <Link to={`${match.url}/props-v-state`} /> } primaryText='Props v. State' />
	</List>

	<Route path={`${match.url}/:topicId`} component={Topic}/>
	<Route exact path={match.url} render={ () => <h3>Please select a topic.</h3> } />
</div>;

export default class
App extends Component {
	componentWillMount() {
		this.setState( { drawerOpen: false } );
	}
	handleOpen = () => { this.setState( { drawerOpen: true } ); };
	handleClose = () => { this.setState( { drawerOpen: false } ); };
	render() {
		return <Router>
			<div>
				<Drawer
					docked={ false }
					open={ this.state.drawerOpen }
					containerStyle={ { top: 64 } }
					onRequestChange={ this.handleClose }
				>
					<List>
						<ListItem
							primaryText='Item 1'
							nestedItems={
								[	<ListItem
										key='0'
										primaryText="Contact"
										containerElement={<Link to="/contact" />}
										onTouchTap={ this.handleClose }
									/>
								,	<ListItem
										key='1'
										primaryText="About"
										containerElement={<Link to="/about" />}
										onTouchTap={ this.handleClose }
									/>
								]
							}
						/>
						<ListItem
							primaryText='Item 2'
							nestedItems={
								[	<ListItem
										key='0'
										primaryText="Home"
										containerElement={<Link to="/" />}
										onTouchTap={ this.handleClose }
									/>
								,	<ListItem
										key='1'
										primaryText="topics"
										containerElement={<Link to="/topics" />}
										onTouchTap={ this.handleClose }
									/>
								]
							}
						/>
						<ListItem
							primaryText='Item 3'
							nestedItems={
								[	<ListItem key='0' value="V3-1" primaryText="T3-1" onTouchTap={ this.handleClose } />
								,	<ListItem key='1' value="V3-2" primaryText="T3-2" onTouchTap={ this.handleClose } />
								]
							}
						/>
					</List>
				</Drawer>

				<AppBar
					title="CRA"
					onLeftIconButtonTouchTap={ this.handleOpen }
				/>

				<Route exact path="/" component={Home}/>
				<Route path="/about" component={About}/>
				<Route path="/contact" component={Contact}/>
				<Route path="/topics" component={Topics}/>
			</div>
		</Router>;
	}
}
```

# 実行

おなじみの

```
npm start
```

したら、ブラウザで localhost:3000 にアクセス。


![SS1.png](https://qiita-image-store.s3.amazonaws.com/0/73493/8bcdebee-70bf-7e8b-988d-dee3f0ae418e.png)
![SS2.png](https://qiita-image-store.s3.amazonaws.com/0/73493/5d7a4ba6-b244-c0b5-1b31-8feedcd9c51a.png)
![SS3.png](https://qiita-image-store.s3.amazonaws.com/0/73493/7bea0383-4ddb-5f21-d1fb-d2e3c50b8a89.png)