Reactハンズオン

# Reactハンズオン

## はじめに
この記事では、ハンズオン形式でReactの基礎を学ぶことができます。JavaScriptがなんとなく読める程度の知識があると読みやすいかと思います。

## 研修の流れ
- Reactとは

- Reactの環境構築
- Reactでカウントアプリ／タスク管理アプリを作ってみる

## Reactとは
ReactはJavaScriptのライブラリです。Reactを使うことでWEBページを独自の記法で簡単に作成することができます。  

### HTMLとかCSSで作らないの？
WEBページの作り方を学ぶ際、はじめにHTMLやCSSを使った作成方法を学ぶかと思います。ReactでWEBページを作成するときも、最終的にはReactの記述を元にhtmlやcssなどのファイルが自動で生成されます。具体的には`npm run build`を実行すると`build`フォルダが生成され、その中にindex.htmlやその他諸々のファイルが生成されます。つまり、`build`フォルダをサーバに置けばサイトを公開することができます。

![build図.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481243/e3d727d0-0ba1-30fd-df90-cd81b1c4e9c5.jpeg)



### Reactの特徴
- コンポーネント単位でページを作成することができる  

> コンポーネントとは、WEBページの各パーツのことです。例えば、ヘッダーとかボタンとかその他諸々  

- コンポーネントを再利用することで簡潔なコードになる

##  Reactの環境構築
Node.jsが入っている前提です。

1. npmを最新にする。
`npm update npm`

1. create-react-appをインストール。
`npm install -g create-react-app`

これでReactの開発環境が整いました。

## Reactでカウントアプリ／タスク管理アプリを作ってみる
### Reactアプリを作成して表示する
1. デスクトップに移動。
`cd デスクトップのパス`  

1. アプリを作成する。
`npx create-react-app my-app`

3. 作成したアプリに移動。
`cd my-app`

4. サーバを立てる。
`npm start`

これでサーバが立ち上がります。ブラウザを立ち上げて`localhost:3000`を開くとWEBサイトが表示できているかと思います。

### Reactアプリの構成
ここで、`my-app`がどのような構成になっているか見てみます。`my-app`をエディタで開いてみてください。

![tree.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481243/fb8a2077-ccf8-25be-7b7e-337ddb8cbd28.png)


フォルダの中にはいくつかのファイルやフォルダがありますが、まず知っておくべきものは`public`と`src`の2つです。

- `public`：Webで公開されるファイルを置いておくフォルダ  

- `src`：Reactのソースコードやそれに関連するデータを置いておくフォルダ  

### HelloWorldを表示してみる
では、今表示されているページの代わりに`HelloWorld`という文字だけのページを表示してみましょう。  
1. src/App.jsの`<div className="App">...</div>`を削除する。  
2. 代わりに`<h2>HelloWorld</h2>`と書き込む。

ブラウザを確認してみると、`HelloWorld`が表示されているかと思います。このように、表示する内容を変更する場合にはreturn内を変更することになります。ここではHTMLの記法で記述することができます。
> 厳密にはJSXという記法になります。HTMLとの違いはほとんどありません。強いて言えば、JSXではタグは必ず閉じなければならないので`<img src="...">`は`<img src="..."></img>`とするか`<img src="" />`とする必要があります。

### 表示処理の流れ
先ほどApp.jsを編集しましたが、変更したデータはどのような流れで処理され表示されるのでしょうか。結論から言うと、先ほど変更したApp.jsのデータは、同じ階層にあるindex.jsに渡された後、`ReactDOM.render`関数によってpublic/index.htmlの`<div id="root"></div>`の子要素として追加されます。

![データの流れ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481243/a674eca3-d9c4-1526-9113-753a03f549e5.jpeg)


## カウントアプリを作ってみる
表示までの流れがわかったところで、実際にカウントアプリを作成してみましょう。今回作成するカウントアプリは、ボタンを押すと表示されている数が+1されるシンプルなものです。  

1. `function App() { ... }`を削除  

2. 代わりに以下のコードを貼り付け  

```
class App extends React.Component {
  render() {
    return (
      <div>
        <h2>タイトル</h2>
        <div>0</div>
        <button>COUNT UP</button>
      </div>
    );
  }
}
```

3. 冒頭部分に`import React from 'react';`を追記。   


ブラウザにカウントアプリのページが表示されているか確認してください。ここでは、`function App() { ... }`を削除し`class App extends React.Component { ... }`に置き換えましたが、どちらもreturn内に記述した要素が表示されるという点は同じです。なぜ置き換えたかや細かい違いは後ほど説明します。

さて、表示されたページにはタイトルとカウント、ボタンが表示されています。現在はボタンを押してもカウント数は変わりません。ではここからReactの記法を使って機能を追加していきましょう。
まずはタイトルを変更していきます。  
1. `render() { ... }`の上に以下を追加
    
```
constructor(props) {
  super(props);
  this.title = "カウントアプリ";
}
```

1. `タイトル`を`{ this.title }`に置き換え

ブラウザを確認すると`タイトル`だった所が`カウントアプリ`になっていると思います。これは、`{ this.title }`の中の`this.title`が`カウントアプリ`に置き換えられたからです。`this.title`はconstructor内で定義されています。

Reactではこのように、`{}`の中にJavaScriptの変数を記述するとReactがhtml要素としてレンダリングしてくれます。
> コメントアウトは`{/* コメント文 */}`で記述できます。  

> `constructor(props) { ... }`や`super(props);`の記述はJavaScriptのclassの用法になります。気になる方は「`javascript class 書き方`」などと調べてみてください。また、Reactでは`constructor`と`super`の引数に`props`を渡すことになっています。はじめのうちはこういうものなんだなぁと思っていただいて大丈夫です。

### Stateを使う
次に、ボタンを押したらカウントアップしてくれる機能を追加します。

1. `super(props);`の下に以下を追加。

```
this.state = {
  count: 0
};
```
1. `render() { ... }`の上に以下のメソッドを追加。

```
countUp() {
  this.setState({count: this.state.count + 1 });
}
```
1. `<div>0</div>`を`<div>{ this.state.count }</div>`に置き換える。

1. `<button>COUNT UP</button>`を
    `<button onClick={ () => { this.countUp() } }>COUNT UP</button>`に置き換える。

ブラウザに戻り、ボタンを押してみてください。カウントが増加しているかと思います。ここでは、ReactのStateという機能を使って`count`の値を管理しています。Stateは、変数を管理する場所のようなイメージです。

![state.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481243/4ed13a66-29fc-ef22-614b-2a66217bafc4.jpeg)


使い方は以下の通りです。

- `constructor`内で`this.state = { 変数名: 値, 変数名: 値, ... }`として初期値を指定

- `this.state.変数名`で値にアクセス

- `this.setState({ 変数名: 新しい値 })`で値を変更

`count`の値を増加させるには`setState`メソッドを実行する必要があります。今回のアプリでは、ボタンを押すと`countUp`メソッドが実行され、`countUp`メソッドの中で`setState`メソッドが呼ばれています。

ボタンが押された時に関数を実行したい場合は、`onClick={ 実行したい関数 }`を属性に追加します。今回は`onClick={ () => { this.countUp() } }`としています。

カウントアプリの作成は以上ですが、countDownのような関数を作成して、ボタンのonClick属性にあてることでカウントダウン機能を実装することもできます。

## タスク管理アプリを作ってみる
では次にタスク管理アプリを作成してみましょう。今回作成するタスク管理アプリはタスク一覧の表示、タスク追加の機能があります。

1. `class App extends React.Component { ... }`を以下に置き換える。

```
class App extends React.Component {
  render() {
    return (
      <div>
        <h2>タスク管理アプリ</h2>
        <input />
        <button>追加</button>
        <div>1. 本を買う</div>
        <div>2. ランニングする</div>
      </div>
    );
  }
}
```

ブラウザでタスク管理アプリが表示されていることを確認してください。今表示されているタスクは直書きです。そのため、一覧機能や追加機能は実装されていません。

では、一覧機能を追加していきましょう。まずはStateを使って、タスクの内容をまとめる配列を管理していきます。

1. `render() { ... }`の上に以下を追加する。

```
constructor(props) {
  super(props);
  this.state = {
    tasks: [
      "本を買う",
      "ランニングする",
      "牛乳を買う"
    ]
  }
}
```

2. 以下のコードを

```
<div>1. 本を買う</div>
<div>2. ランニングする</div>
```
以下に置き換える。

```
{
  this.state.tasks.map( (task, index) => {
    return <div>{ index + 1 }. { task }</div>
  })
}
```
ブラウザを確認すると、Stateのtasksで管理しているタスクが表示されているかと思います。書き換えた内容を順を追って説明していくと、

- 1.で、タスクを管理する`tasks`配列をStateの変数として定義。

- 2.で、`tasks`配列の中身を取り出して表示。

となります。2.はやや複雑ですが分解して考えるとそれほど難しくありません。

ポイントは、

- アロー関数表記

- mapメソッド
- returnの値

の３つです。

#### アロー関数表記
まずはアロー関数表記ですが、これは従来の関数の書き方を簡潔にした表記方法です。

```使用例
// 従来
function sayHi(name) {
  const msg = "hi " + name;
  console.log(msg);
}
sayHi("Bob"); // hi Bob

// アロー関数表記
const sayHi = (name) => {
  const msg = "hi " + name;
  console.log(msg);
};
sayHi("Bob"); // hi Bob
```

慣れてしまえば難しくはありません。今はこういう書き方があるんだなぁくらいに思ってもらえれば大丈夫です。

#### mapメソッド
mapメソッドは、配列の各要素に対してある処理を行うメソッドで、
`配列.map(処理が書かれた関数)`のように書きます。
例えば、配列`array1`の各要素を2倍した値からなる配列`array2`を得る場合は以下のように書けます。

```
const array1 = [2, 4, 5, 8];
const array2 = array1.map( (value) => {
  return value * 2;
});
console.log(array2); // [ 4, 8, 10, 16 ]
```
> mapメソッドが引数にとっている関数の第一引数には配列の要素が入ります。第二引数をとると、取り出した要素のインデックスを取得できます。

#### returnの値
最後にreturnの値についてです。Reactではhtml要素を一つの値のように扱うことができます。
例えば、

```
const element = <h2>タスク管理アプリ</h2>
```
といった扱いができます。

以上を踏まえ、改めて2.で置き換えた箇所を見てみると、

```
{
  this.state.tasks.map( (task, index) => {
    return <div>{index + 1}. {task}</div>
  })
}
```
tasks配列に対してmapメソッドを使用し、mapメソッドの引数に、アロー関数表記で処理したい内容を記述していることがわかります。mapメソッドのreturnではhtml要素が返されています。

では次に、タスクの追加機能を実装したいと思います。

1. Stateに`taskContent: ""`を追加する。

1. inputタグの属性に
    `value={ this.state.taskContent }`と
    `onChange={(e) => { this.setState({ taskContent: e.target.value }) }}`
    を追加。
1. buttonタグの属性に
    `onClick={ () => { this.addTask() } }`を追加。
1. `render() { ... }`の上に以下を追加。

```
addTask() {
  let tasks = this.state.tasks;
  tasks.push(this.state.taskContent);
  this.setState({tasks: tasks});
  this.state.taskContent = "";
}
```
ブラウザで、テキストフィールドに適当なタスク内容を記入して追加ボタンを押してみてください。タスクが追加されたのがわかります。

追記した内容を順に説明すると、

- 1.でテキストフィールドの値を保持するtaskContent変数をStateにて初期化

- 2.では、
    - taskContentの値をテキストフィールドに表示
    - テキストフィールドに入力された値をtaskContentに反映
- 3.でボタンをクリックした時にaddTask関数を実行するように指定
- 4.でaddTask関数を定義

addTask関数でtaskContentの値をStateのtasks配列に追加しています。


### コンポーネントとProps
ここまでで、一覧機能と追加機能を実装することができました。ここで、コンポーネント設計の考え方を導入してタスクの表示パーツをコンポーネント化してみましょう。コンポーネント化することでより簡潔なコードで記述することができます。

1. `src`フォルダの中に`components`フォルダを作成。


1. 作成した`components`フォルダの中に`Task.js`というファイルを作成。
1. `Task.js`に以下を貼り付ける。

```
import React from 'react';

class Task extends React.Component {
  constructor(props) {
    super(props);
    this.number = props.number;
    this.task = props.task;
  }
  render() {
    return (
      <div>
        { this.number }. { this.task }
      </div>
    );
  }
}

export default Task;
```
1. `App.js`の冒頭部分に
    `import Task from './components/Task.js';`
    を追記してTask.jsをインポート。

1. mapメソッドの戻り値になっている`<div>...</div>`を
    `<Task number={index + 1} task={task}/>`に置き換える。

ブラウザを確認して問題なくページが表示されているか確認してください。

手順を順に解説していくと、

- タスクを表示するパーツを`Task`コンポーネントにして置き換えたい

- コンポーネントをまとめる`components`フォルダを作成し、その中に`Task.js`を作成
- `Task.js`の中身も`App.js`と同様の構造で、Taskクラスコンポーネントをエクスポートしている
- そのエクスポートされたTaskクラスを`App.js`の冒頭部分でインポート
- `App.js`のmapメソッドの戻り値として<Task ... />を置く
という流れになります。
ここで、`<Task .../>`の`...`に当たる部分を見てみます。`number={index + 1} task={task}`とありますが、ここで`Task`に`number`と`task`という`props`を渡しています。`props`とはコンポーネントに渡す値のことです。
この2つの`props`がどのように使われているか`Task.js`を確認してみると、`constructor`内で`this.number = props.number; this.task = props.task;`
としてクラス内の変数に渡されていることが分かります。このようにコンポーネントに渡された`props` の値は、`props.props名`とすることでコンポーネント内で使用することができます。


![コンポーネントとprops.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481243/eb2c1f8f-d3dc-a537-f8e8-819e3474c4ed.jpeg)

今回の例では、コンポーネント化のメリットをあまり感じられなかったかもしれませんが、もう少し大きな開発になってくるとコードの見易さや管理のし易さ、再利用性の観点からメリットが大きくなります。

以上で、2つのアプリの実装が完了しました！

### 関数コンポーネントとは
Reactのコンポーネントにはクラスコンポーネントと関数コンポーネントの2種類のコンポーネントがあります。
今まで書いてきたコンポーネントはクラスコンポーネントです。

```クラスコンポーネント
class コンポーネント名 extends React.component {
  render() {
    return (
      <div>
        表示内容
      </div>
    );
  }
}
```
一方、関数コンポーネントは次のような書き方です。

```
// アロー関数表記で書かれることもある
function コンポーネント名() {
  return (
    <div>
      表示内容
    </div>
  );
}
```
関数コンポーネントはクラスコンポーネントよりも簡潔に書けるといったメリットがあります。クラスコンポーネントで出来ることは基本的には関数コンポーネントでも実装できますが、少し難解な記法を使ったりするのでクラスコンポーネントに慣れてから関数コンポーネントを触ってみると理解しやすいかと思います。
> はじめに`function App() { ... }`を削除してクラスコンポーネントに置き換えたのはこのためです。

以上でReactハンズオンは修了です。お疲れ様でした。

## 紹介しきれなかったこと
- ReactHooks
- ReactRouter
- Redux