Reactでコンポーネントを作ってみる。

### コンポーネントとは

コンポーネント(Component)とは、特定の機能を持った汎用的な部品のことです。
ボタンやテキストボックス、リストなどもソフトウェアを構成する部品(=コンポーネント)と言えます。

それぞれのパーツをコンポーネントとして扱うことにより、取り外しできるレゴのパーツみたいに再利用可能となります。

### とりあえずコンポーネントを作ってみる

Reactでコンポーネントを作ってみます。

前回の記事で作成した`create-react-app`の環境をそのまま使っていきます。
https://qiita.com/sho7/items/bb564e22a096eaea9877

このサンプルのディレクトリ構成は以下の通りです。

<img width="237" alt="Project — ~:Documents:git_repo:examples 2018-01-02 19-06-47.png" src="https://qiita-image-store.s3.amazonaws.com/0/226431/5666420d-ddae-01fc-2544-933f227be32e.png">

`public/index.html`に以下のように記載します。

```html:public/index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="theme-color" content="#000000">
    <!--
      manifest.json provides metadata used when your web app is added to the
      homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React App</title>
  </head>
  <body>
    <noscript>
      You need to enable JavaScript to run this app.
    </noscript>
    <div id="root"></div>
    <div id="myForm"></div>
    <br/>
    <br/>
    <div id="myButton"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
  </body>
</html>

```

次に`src/components`ディレクトリ以下に`MyForm.js`を作ってみます。

```javascript:src/components/MyForm.js
import React from 'react'

export default class MyForm extends React.Component {
  constructor (props) {
    super(props)
    this.state = {value:''}
  }

  doChange (e) {
    const newValue = e.target.value
    this.setState({value: newValue})
  }

  doSubmit (e) {
    window.alert('Input value is ' + this.state.value)
    e.preventDefault()
  }

  render () {
    const doSubmit = (e) => this.doSubmit(e)
    const doChange = (e) => this.doChange(e)
    return (
      <form onSubmit={doSubmit}>
        <input type='text'
         value={this.state.value}
         onChange={doChange} />
        <input type='submit' value='send' />
      </form>
    )
  }
}

```

`src/index.js`に`ReactDOM.render`を追加します。

```javascript:src/index.js`
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import MyForm from './components/MyForm'
import MyButton from './components/MyButton'
import registerServiceWorker from './registerServiceWorker';



ReactDOM.render(<App />, document.getElementById('root'));
ReactDOM.render(<MyForm />, document.getElementById('myForm'));
ReactDOM.render(<MyButton />, document.getElementById('myButton'));
registerServiceWorker();
```

すると、以下のようにフォームが追加されます。
```
yarn start -s
```

<img width="430" alt="React App 2018-01-02 19-11-38.png" src="https://qiita-image-store.s3.amazonaws.com/0/226431/880410b1-37fe-e37c-16f7-acafb390b398.png">


### マテリアルデザインを取り入れてみる
 
適当に作ってきたコンポーネントをそれっぽいデザインにするために、`material-ui`を取り入れてみます。

以下のページを参考にしています。
https://www.npmjs.com/package/material-ui
https://github.com/callemall/material-ui-webpack-example/blob/25938ac6f5db94645e6ea9f24a903792d3133c5d/src/app/Main.js
http://www.material-ui.com/#/components/raised-button

以下のコマンドでmaterial-uiをインストールします。
```
npm install material-ui
```

しかし、サンプル見よう見まねで作った以下の書き方では思わぬエラーが出てしまいます。

```javascript:src/components/MyButton.js
import React,  {Component}  from 'react';
import RaisedButton from 'material-ui/RaisedButton';

export default class MyButton extends Component {
  handleTouchTap() {
    this.setState({
      open: true,
    });
  }

  render() {
    return (
      <RaisedButton
        label="My Button Example"
        secondary={true}
        onTouchTap={this.handleTouchTap}
      />
    )
  }
}

```

出てくるのは以下のようなメッセージです。

```
TypeError: Cannot read property 'prepareStyles' of undefined
```

```javascript:RaisedButton.js
  291 |     secondary = _props.secondary,
  292 |     style = _props.style,
  293 |     other = (0, _objectWithoutProperties3.default)(_props, ['backgroundColor', 'buttonStyle', 'children', 'className', 'disabled', 'disabledBackgroundColor', 'disabledLabelColor', 'fullWidth', 'icon', 'label', 'labelColor', 'labelPosition', 'labelStyle', 'overlayStyle', 'primary', 'rippleStyle', 'secondary', 'style']);
> 294 | var prepareStyles = this.context.muiTheme.prepareStyles;
  295 | 
  296 | var styles = getStyles(this.props, this.context, this.state);
  297 | var mergedRippleStyles = (0, _simpleAssign2.default)({}, styles.ripple, rippleStyle);
```

こちらを解消するためには、`MuiThemeProvider`をimportして、タグを`<MuiThemeProvider>`でラップする必要があります。

```javascript:src/components/MyButton.js
import React,  {Component}  from 'react';
import RaisedButton from 'material-ui/RaisedButton';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'

export default class MyButton extends Component {

  handleClick() {
    console.log('button is clicked')
  }

  render() {
    return (
      <MuiThemeProvider>
        <RaisedButton
          label="My Button Example"
          secondary={true}
          onClick={this.handleClick}
        />
      </MuiThemeProvider>
    )
  }
}
```

https://stackoverflow.com/questions/39863436/typeerror-cannot-read-property-preparestyles-of-undefined

上記の対応でエラーを解消したところ、以下のようにマテリアルデザインっぽいボタンが表示されました。

```
yarn start -s
```

<img width="468" alt="React App 2018-01-02 19-15-55.png" src="https://qiita-image-store.s3.amazonaws.com/0/226431/69658455-8d2c-da2e-92e8-a9633220121e.png">


### JavaScript構文を調べる

- export  
変数をモジュール外部に公開することができます。

> export 文は、指定したファイル (またはモジュール) から関数、オブジェクト、プリミティブをエクスポートするために使用します。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/export

exportで外部に公開されたモジュールを利用する側では`import`を使います。
この記事がわかりやすいです。
http://analogic.jp/module-summary/#es2015-module

- default  
importする際に特に指定がなければdefaultで指定されたクラスや関数を呼びます。

こちらの記事もわかりやすいです。
http://numb86-tech.hatenablog.com/entry/2016/10/19/153606