React超概要

社内でReactの勉強会をした時に作成した、**Reactの基本となる用語や考え方**をついて紹介します。Reactに興味がある方に、少しでも多くの人にReactについて慣れ親しんでもらえると嬉しいです。

## 前提事項
* React 16.8から導入された[hooks](https://ja.reactjs.org/docs/hooks-intro.html)を利用した記法に則って記載しております
* JavaScript(ES6)の構文をベースに記載をしております

### アロー関数
ES6から使えるようになった記法です。下記のように関数を宣言することができます

```javascript
// 通常の記法
fuction hogehoge() {
}

// アロー関数を使った関数宣言
const hogehoge = () => {
}
```

* [アロー関数 - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions)

## import
他のモジュールをimportすることができます。reactでは一般的にnpm経由でインストールしたファイルを読み込んで利用します。

```javascript
import React from 'react';
import ReactDOM from 'react-dom';
```

* [import - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/import)

## Reactとは？
Reactとは、ユーザインターフェイスを作るためのJavaScriptのライブラリです。（よく間違われますが、フレームワークではないそうです。）

UIをコンポーネント（部品）と呼ばれる単位で作成するのが特徴で、この組み合わせで複雑なUIを柔軟に構成することができます。React要素と呼ばれる仮想DOMを生成、これをもとにレンダリングをします。

## ReactでHello World!
下記のように書くことができます。

**HTMLファイル**

```htmlmixed
<div id="root"></div>
```
**JSファイル**

```javascript
import React from 'react';
import ReactDOM from 'react-dom';

const element = <div>Hello, world</div>;
ReactDOM.render(
  element,
  document.getElementById('root')
);
```
なんか見慣れない構文が出てきましたね。。。
１つずつ解説していきます！

## JSXとは?
上記でelementに格納された値は、JSXと呼ばれ、React要素を簡単に記述することのできる方法です。これにより、htmlをJsのなかに書いているような感覚で記述ができます。

実際にはReact.createElementに変換されていますので下記の文面は同義です。基本的にはJSXで書いていけば大丈夫です。

```javascript
// JSX
const yesJsx = <div>Hello, world</div>;

// React.createElement
const noJsx = React.createElement('div', null, 'Hello World');
```

[JSX なしで React を使う – React](https://ja.reactjs.org/docs/react-without-jsx.html)

## JSXで変数展開
JSX内では中括弧{}で囲むことで変数を展開することができます

```javascript
const displayText = 'HelloWorld';
const HelloWorld = () => {
  return (
    <div>
      <p>{ displayText }</p>
    </div>
  )
}
```

## NGなJSXの例
JSXは基本的には一つのエレメントしか返すことができません。下記のようにreturnするエレメントが2つ以上あるとエラーとなります。

```javascript
// エラーが出ます
import React from 'react';

const HelloWorld = () => {
  return (
    <div>
      <p>HelloWorld</p>
    </div>
    <div>
      <p>HelloWorld</p>
    </div>
  )
}

```

ただ、divのなかに囲ってあげると正常に動作します。

```javascript
import React from 'react';

const HelloWorld = () => {
  return (
    <div>
      <div>
        <p>HelloWorld</p>
      </div>
      <div>
        <p>HelloWorld</p>
      </div>
    </div>
  )
}

```

### 複数の要素を返すことはできないのか？
実は、複数の要素を返す方法として**「Fragment(フラグメント)」**というものがあります。

ここではあまり詳しく言及はしませんが、実施に書いていると、複数の要素を返したい場合も出てくるので、その際はこの記法を活用することで解消することができます！
[フラグメント – React](https://ja.reactjs.org/docs/fragments.html)

P.S @uitspitss さん、コメントいただきありがとうございます！

## コンポーネントとは？
コンポーネントとは、UIの構成要素のことです。この部品を組み合わせて1つのページを作成していきます。実際はコンポーネント単位でjsファイルを作成し、importして呼び出すことが多いですが、今回はあまり気にせずに書いていきます。

例として、公式のチュートリアルにある三目ゲーム（⭕️❌ゲーム）のUIを例に説明します。下記の画像をご覧ください。
![スクリーンショット 2020-09-30 19.50.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278426/b5dcfc69-79c7-398c-e81e-af2011f75ed4.png)

このようなUIがあったとして、Reactではこれを３つのコンポーネントに分けて考えます。１つはページ全体のGame、盤面を表すBoard、最後にマス目１つ１つを表すSquareです。Squareに関しては9つ存在することになります。
![スクリーンショット 2020-09-30 19.59.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278426/80953337-3c13-ada0-26ce-973f5f895700.png)

このような単位のことをコンポーネントと呼びます。コードに表すと下記のような感じです。

```javascript
// 三目並べゲームのコンポーネント
import React from 'react';

// 盤面のマス１つ１つのコンポーネント
const Square = (props) => {
  // 省略
}

// 盤面全体のコンポーネント
const Board = () => {
  // 省略
}

// ページ全体のコンポーネント
const Game = () => {
  // 省略
}

```
[Tic Tac Toe](https://codepen.io/gaearon/pen/EmmOqJ?editors=0010)
[チュートリアル：React の導入 – React](https://ja.reactjs.org/tutorial/tutorial.html)

## stateとpropsについて
コンポーネントで使われる概念のうち、最初に覚えておきたいのがstateとpropsです。

* stateはコンポーネントの内部で制御される値のことです
* propsは親(呼び出し元)コンポーネントから受け取る値のことで基本読み取り専用になります

ちなみにpropsはpropertiesを略したものです。

この２つの値を**コンポーネント間で受け渡す事で、複雑なUIを制御する**ことができます


## state
stateはコンポーネントの内部で制御される値のことです。そのため基本的には他のコンポーネントから制御できません。

また、stateが更新されると同時にコンポーネントの値が再レンダーされます。下記のコードでは、useStateというAPIを使う事でstateを管理しています。

下記の例ではBoard（盤面）コンポーネントにて9つのsquares（マス）の状態と、プレイヤーの順番の状態をstateで管理しています。

```javascript
import React, { useState } from 'react'; // hooks

const Board = () => {
  // コンストラクタ
  const [squares, setSquares] = useState(Array(9).fill(null));
  const [xIsNext, setXIsNext] = useState(true);

  // 以下省略 
}
```

## propsを子コンポーネントに渡す
BoardコンポーネントからSquareコンポーネントを呼び出すときにvalueとonclickにpropsを渡しています。この時、変数だけでなく関数を渡す事もできます。

```javascript
const Board = () => {
  const squares = [0, 1, 2]
  const handleClick = (i) {
    // 省略
  }
  return (
    <Square value={squares} onClick={() => handleClick(i)}/>
  );
}
```

## propsを受け取り、参照する
Squareコンポーネントは引数としてpropsを受け取ります。

props自体はオブジェクト構造となっており、props.xxxという記法で呼び出すことができます。下記の例ではvalueの中身の表示と、親コンポーネントの関数の実行をしています

```javascript
const Square = (props) => {
  return (
    <button className="square" onClick={() => props.onClick()}>
      {props.value}
    </button>
  ); 
}
```


## ご参考 〜Reactで書く三目並べ（⭕️❌ゲーム）のコード〜
最終的なコードは下記になります。

公式の[チュートリアル：React の導入 – React](https://ja.reactjs.org/tutorial/tutorial.html)にも書かれているゲームのコードです。公式チュートリアルではコンポーネントの記法が少し古いため、Hooksで書き換えております。

```javascript
import React, { useState } from 'react';
import ReactDOM from 'react-dom';

// controlled component
const Square = (props) => {
  return (
    <button className="square" onClick={() => props.onClick()}>
      {props.value}
    </button>
  ); 
}

const Board = () => {
  const [squares, setSquares] = useState(Array(9).fill(null));
  const [xIsNext, setXIsNext] = useState(true);

  const handleClick = (i) => {
    const cloneSquares = squares.slice();
    if (calculateWinner(cloneSquares) || cloneSquares[i]) {
      return;
    }
    cloneSquares[i] = xIsNext ? 'X' : 'O';
    setSquares(cloneSquares);
    setXIsNext(!xIsNext);
  }

  const renderSquare = (i) => {
    return (
      <Square
        value={squares[i]}
        onClick={() => handleClick(i)}
      />
    );
  }

  const winner = calculateWinner(squares);
  
  let status;
  if (winner) {
    status = 'Winner: ' + winner;
  } else {
    status = 'Next player: ' + (xIsNext ? 'X' : 'O');
  }

  return (
    <div>
      <div className="status">{status}</div>
      <div className="board-row">
        {renderSquare(0)}
        {renderSquare(1)}
        {renderSquare(2)}
      </div>
      <div className="board-row">
        {renderSquare(3)}
        {renderSquare(4)}
        {renderSquare(5)}
      </div>
      <div className="board-row">
        {renderSquare(6)}
        {renderSquare(7)}
        {renderSquare(8)}
      </div>
    </div>
  );
}

const Game = () => {
  return (
    <div className="game">
      <div className="game-board">
        <Board />
      </div>
      <div className="game-info">
        <div>{/* status */}</div>
        <ol>{/* TODO */}</ol>
      </div>
    </div>
  );
}

const calculateWinner = squares => {
  const lines = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];
  for (let i = 0; i < lines.length; i++) {
    const [a, b, c] = lines[i];
    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
      return squares[a];
    }
  }
  return null;
}

// ========================================

ReactDOM.render(
  <Game />,
  document.getElementById('root')
);
```

## おさらい
* ReactはJavascriptのライブラリである
* Javascript(ES6)の構文がベースとなっている
* JSXという記法を使った仮想DOMを記述することができる
* コンポーネントベースでUIを生成する
* コンポーネントではstateとpropsを駆使して柔軟なUIを作成することができる
* stateはコンポーネント内部で制御する値のこと（外部から変更はできない）
* propsは基本参照のみだが、親コンポーネントの関数を渡すことができる

## まとめ
少しでもReactに関心を持ってくだされば幸いです！

## 参考リンク
* [アロー関数 - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
* [import - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/import)
* [チュートリアル：React の導入 – React](https://ja.reactjs.org/tutorial/tutorial.html)
* [ステートフックの利用法 – React](https://ja.reactjs.org/docs/hooks-state.html)
* [【最新版・hooks対応】 Reactの基礎を学んでTODOアプリを作ろう！｜宮川 竜太朗｜note](https://note.com/dragontaro/n/n04e0b9c0cca7)
* [Reactの学習、今からやるならこうする \- Qiita](https://qiita.com/d0ne1s/items/971ffc8db6815e9aaad0)