Reactアプリケーション開発入門


## ■create-react-appのインストール&Hello Worldの表示

create-react-appはFacebookが提供しているCLIツールです。
環境構築の手間をスキップして学習に集中できます。

```
// create-react-appのインストール
yarn global add create-react-app

// Reactアプリケーションの作成
create-react-app hello-world

// hello-worldに移動
cd hello-world

// 開発開始
yarn start
```

![7b695480-013f-11eb-82ee-a6989fc53549.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911450/a3e2619f-da85-2bf9-3b2b-728aa3099751.png)


ファイル構造はこんなかんじです。
![7b695480-013f-11eb-9223-07d42cd3a344.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911450/4f227789-5c4c-81de-87a9-469da897f637.png)


Hello Worldを表示するにはsrc/App.js内をこのように書き換えます。

```Javascript
import React from 'react';
import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code>and save to reload {/* この行を「Hello World」に書き換える */}
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;
```

これでHello Worldが表示されました。
![7c01eb00-013f-11eb-8f31-3b24ac4893e5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911450/d7020cb5-66db-d640-327d-f02daeae7300.png)

ちなみにこのreturn()内の部分はぱっと見HTMLに見えますが、実際はJSXというものになっています。
詳細は公式をご確認ください。( https://ja.reactjs.org/docs/introducing-jsx.html )

```Javascript
import React from 'react';
import logo from './logo.svg';
import './App.css';

function App() {
  //このreturnの中がJSX
  return ( 
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Hello World
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;
```

## ■コンポーネントについて
Reactのコンポーネントには「関数コンポーネント」と「クラスコンポーネント」の二種類があります。

### <関数コンポーネント>
実は先ほどのHello Worldを表示した時のApp.jsが既に関数コンポーネントの形になっていました。

```Javascript
import React from 'react';
import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Hello World
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;
```

わかりやすく余計な部分を省いた形が下記になります。
※ちなみにですが、JSXが内部的にReactを使用しているため「import React from 'react';」の記述を無くすとエラーになります。

```Javascript
import React from 'react';

function FunctionComponentA() {
  return (
    <div className="function-component_A">
      function-component_Aです。
    </div>
  );
}

export default FunctionComponentA;
```

このようにsrc/index.jsに追加することで反映されます。

```Javascript
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import FunctionComponentA from './FunctionComponentA'　//ここに追加
import * as serviceWorker from './serviceWorker';

ReactDOM.render(
  <React.StrictMode>
    <FunctionComponentA /> {/* ここに追加 */}
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
```
![7c9a8180-013f-11eb-8449-abdbaf2c3e57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911450/0760acf8-65c5-4be8-ea16-945280bc0c8a.png)

このようにアロー関数の形で定義することもできます。

```Javascript
import React from 'react';

const FunctionComponentB = () => {
  return (
    <div className="function-component_B">
      function-component_Bです。
    </div>
  );
}

export default FunctionComponentB;
```

### <クラスコンポーネント>

クラスコンポーネントはこのように定義します。

```Javascript
import React, { Component } from 'react';

class ClassComponent extends Component {
  render() {
    return (
      <div className="class-component">
        ClassComponentです。
      </div>
    )
  }
}

export default ClassComponent;
```

Componentを継承したクラスとして定義します。

### <関数コンポーネントとクラスコンポーネントそれぞれの特徴>

<strong>関数コンポーネント</strong>
・簡潔に書けるので基本はこちらが望ましい。
・状態管理によるレンダー制御ができない。

<strong>クラスコンポーネント</strong>
・状態管理によるレンダー制御が可能。
・ローカルstateやライフサイクルメソッドが利用可能。

## ■props
こちらが見本になります。

```Javascript
import React from 'react';

const Parent = () => {
  return (
    <div>
      <strong>表示されるとこうなります。</strong>
      <Child name={"ポール・マッカートニー"} instrument={"ベース"} />
      <Child name={"ジョン・レノン"} instrument={"ギター"} />
      <Child name={"ジョージ・ハリスン"} instrument={"ギター"} />
      <Child name={"リンゴ・スター"} instrument={"ドラム"} />
    </div>
  )
}

const Child = (props) => {
  return (
    <div>僕は{props.name}です。担当は{props.instrument}です。</div>
  )
}

export default Parent;
```

![7dcbae80-013f-11eb-8c85-0e24cc520e73.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911450/32863061-1095-e1b0-c929-d6988eb35338.png)

Child(子コポーネント)をParent(親コンポーネント)で利用する際に属性のような形でpropsを渡すことができます。
渡ったpropsはChild側で受け取り、利用するという流れになります。

データを配列で一括に渡したいと言う時には、「map」を利用することで実現可能です。
下記キャプチャでは、配列ビートルズをmapで展開しています。

```Javascript
import React from 'react';

const Parent2 = () => {
  const beatles = [
    {
      name: "ポール・マッカートニー",
      instrument: "ベース"
    },
    {
      name: "ジョン・レノン",
      instrument: "ギター"
    },
    {
      name: "ジョージ・ハリスン",
      instrument: "ギター"
    },
    {
      name: "リンゴ・スター",
      instrument: "ドラム"
    }
  ]
  return (
    <div>
      <strong>表示されるとこうなります。(map)</strong>
      {
        beatles.map((beatlesMember, index) => {
          return <Child name={beatlesMember.name} instrument={beatlesMember.instrument} key={index} />
        })
      }
    </div>
  )
}

const Child = (props) => {
  return (
    <div>僕は{props.name}です。担当は{props.instrument}です。</div>
  )
}

export default Parent2;
```


## ■prop-types(型チェック)
こちらが見本になります。

```Javascript
import React from 'react';
import PropTypes from 'prop-types' //これをimportします。

const Parent = () => {
  return (
    <div>
      <strong>表示されるとこうなります。</strong>
      <Child name={"ポール・マッカートニー"} year={1942} guitar={true} />
      <Child name={"ジョン・レノン"} year={1940} guitar={true} />
      <Child name={"ジョージ・ハリスン"} year={1943} guitar={true} />
      <Child name={"リンゴ・スター"} year={1940} guitar={false} />
    </div>
  )
}

const Child = (props) => {
  return (
  <div>僕は{props.name}です。{props.year}年生まれです。{props.guitar ? 'ギターを弾けます。' : 'ギターは弾けません。'}</div>
  )
}

//ここでpropsに対しての型定義を行っています。
Child.propTypes = {
  name: PropTypes.string,
  year: PropTypes.number,
  guitar: PropTypes.bool
}

export default Parent;
```

prop-typesを導入する手順としては、
1. PropTypesをimportする。
2. コンポーネントのpropsに対して型定義を行う。
になります。

●動作確認
「name="リンゴ・スター"」の部分のyearとguitarの値を文字列に変えてみます。

```Javascript
import React from 'react';
import PropTypes from 'prop-types' //これをimportします。

const Parent = () => {
  return (
    <div>
      <strong>表示されるとこうなります。</strong>
      <Child name={"ポール・マッカートニー"} year={1942} guitar={true} />
      <Child name={"ジョン・レノン"} year={1940} guitar={true} />
      <Child name={"ジョージ・ハリスン"} year={1943} guitar={true} />
      <Child name={"リンゴ・スター"} year={"1940"} guitar={"false"} /> {/* ここの値を間違ったもの(文字列)に変更 */}
    </div>
  )
}

const Child = (props) => {
  return (
  <div>僕は{props.name}です。{props.year}年生まれです。{props.guitar ? 'ギターを弾けます。' : 'ギターは弾けません。'}</div>
  )
}

//ここでpropsに対しての型定義を行っています。
Child.propTypes = {
  name: PropTypes.string,
  year: PropTypes.number,
  guitar: PropTypes.bool
}

export default Parent;
```

![7efcdb80-013f-11eb-8bb6-08f6fd378bcd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911450/a2aa992c-d64d-baee-3e66-a9a712f3554a.png)


無事にエラーが吐き出されました。

## ■state
こちらが見本になります。
countというstateを持ったCounterコンポーネントを作成しました。

```Javascript
import React, { Component } from 'react';

class Counter extends Component {
  // 状態を持たせるための処理
  constructor(props) { // コンポーネントの初期化時に呼び出される
    super(props)
    // this.stateでstateにアクセスできる。
    this.state = { count: 0 }
  }

  countUp = () => {
    this.setState({ count: this.state.count + 1 }) // stateを変更する時は必ずsetState()を使用する。
  }

  countDown = () => {
    this.setState({ count: this.state.count - 1 }) // stateを変更する時は必ずsetState()を使用する。
  }

  render() {
    return (
      <div className="counter">
        <div>count:{ this.state.count }</div>
        <button onClick={this.countUp}>+1</button>
        <button onClick={this.countDown}>-1</button>
      </div>
    )
  }
}

export default Counter;
```

![7f957200-013f-11eb-9bd5-315fd9447874.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911450/63f9e4ed-5615-e73f-bb4b-fa4762bacebb.png)


以下、ポイントになります。<br>
・レンダー制御が必要なのでクラスコンポーネントで作成した。
・stateの値を変更する時はsetState()を必ず使用する。
・this.stateでstateにアクセスする。

[:christmas_tree: FORK Advent Calendar 2020](/advent-calendar/2020/fork)
:arrow_left: 16日目 [Full Static Generationを試す](/AsaToBan/items/a2f172c45ca12e5e52dc) @AsaToBan
:arrow_right: 18日目 [Reactで神経衰弱を作ってみた](/ktn/items/054140bb496a707fafbf) @ktn