Reactを学ぶ上で知っておくべきJavaScriptの基本概念

## はじめに

今回は[FlyCode氏](https://twitter.com/FlycodeHQ)が紹介していた、Reactを学ぶ上で知っておくべきJavaScriptの基本概念を紹介します。

具体的なJavaScriptでのコード解説と、Reactではそれがどのように使われるのかを紹介します。

## この記事の対象者

- JavaScriptのよく使う基本文法を学びたい人
- Reactの初心者から中級者

## この記事の目標

- React開発でよく使われるJavaScriptの文法や処理を理解する

## JavaScriptの基礎文法

本記事では下記の7つをピックアップして紹介します

- 三項演算子
- 分割代入
- スプレッド構文
- 配列操作
- アロー関数
- 非同期処理(Async/Await/Promise)
- APIコール

### 三項演算子

三項演算子はMDNでは下記のように解説されています。

> 条件 (三項) 演算子は JavaScript では唯一の、3 つのオペランドをとる演算子です。

三項演算子の構文
```js
condition ? exprIfTrue : exprIfFalse
```

- ``condition``は値が条件として使用される式
- ``exprIfTrue``は``condition``が``true``と評価された場合に評価される式
- ``exprIfFalse`` は``condition``が``false``と評価された場合に評価される式

JavaScriptコードで具体例を見ていきます。
```js
  const flag = true;
  const text = flag ? "flagはtrueです" : "flagはfalseです";
  console.log(text);
```

三項演算子で条件して使用される式(`` flag``)が``true``なので``console.log``では「flagはtrueです」が出力されています。
![スクリーンショット 2022-10-15 7.58.39.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/1c7b4b4c-49bf-cead-b6bd-5dc357491c08.jpeg)

``flag``の値を``false``に書き換えると「flagはfalseです」が出力されます。
```js
  const flag = false;
  const text = flag ? "flagはtrueです" : "flagはfalseです";
  console.log(text);
```

![スクリーンショット 2022-10-15 8.00.30.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/a516c04d-e68c-a8e1-48c2-dc7f07dd095b.jpeg)

三項演算子はReact開発ではコンポーネントの出し分けで使われることが多いです。

```jsx
const Test: React.FC = () => {
  const [isLoading, setIsLoading] = useState<boolean>(true);
  return <>{isLoading ? <Loading /> : <Contents />}</>;
};
```

上記は``isLoading``が``true``だった場合は``<Loading  />``が表示され、``false``だった場合は``<Contents />``が表示されます。

今回は``isLoading``に初期値として``true``が入っているので``<Loading  />``が表示されます。

### 分割代入

分割代入はMDNにおいて

> 分割代入 (Destructuring assignment) 構文は、配列から値を取り出して、あるいはオブジェクトからプロパティを取り出して別個の変数に代入することを可能にする JavaScript の式です。

と書いてあります。

JavaScriptコードで具体的に見ていきます。

```js
let a,b;
[a,b] = [10,20]
console.log(a)
// 10
console.log(b)
// 20
```

分割構文はReact開発において``props``の受け渡しの際に使われることがあります。

**【propsを受け取る子コンポーネント】**
```jsx
type ContentsProps = {
  name: string;
  age: number;
};

const Contents: React.FC<ContentsProps> = (props) => {
  //　propsを分割代入
  const { name, age } = props;
  return (
    <>
      <p>名前:{name}</p>
      <p>年齢:{age}</p>
    </>
  );
};
```
**【propsの値を受け渡す親コンポーネント】**
```jsx
const Parent: React.FC = () => {
  return <Contents name={"taro"} age={18} />;
};
```
![スクリーンショット 2022-10-15 8.26.09.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/7d31e0c9-6da5-12cc-74c6-e4d6f0918b6f.jpeg)

### スプレッド構文

スプレッド構文はMDNにおいて

> スプレッド構文 (...) を使うと、配列式や文字列などの反復可能オブジェクトを、0 個以上の引数 (関数呼び出しの場合) や要素 (配列リテラルの場合) を期待された場所で展開したり、オブジェクト式を、0 個以上のキーと値の組 (オブジェクトリテラルの場合) を期待された場所で展開したりすることができます。

と記載されています。

文章だけだとわかりにくいので、具体的なJavaScriptコードを見ていきます。

```js
  const array = [1, 2, 3];
  // コピーの作成
  const copy_array = [...array]; // => [1, 2, 3]
  // 要素を追加し新しい配列を生成
  const new_array = [...array, 4, 5]; // => [1, 2, 3 ,4, 5]
  // 二つの配列をマージする
  const merge_array = [...array, ...new_array]; // => [1 ,2 , 3 , 1, 2, 3 ,4, 5]
```

スプレッド構文はReact開発においては配列やオブジェクトの`state``更新で使われます。

```jsx
  const [fruits, setFruits] = useState<string[]>([
    "りんご",
    "みかん",
    "ぶどう",
  ]);

  // イチゴを追加
  const addStrawberry = () => {
    const copy = [...fruits];
    copy.push("いちご");
    setFruits(copy);
  };

  return (
    <>
      {fruits.map((fruit, index) => (
        <p key={index}>{fruit}</p>
      ))}
      <button onClick={addStrawberry}>いちごを追加</button>
    </>
  );
```

![スクリーンショット 2022-10-15 8.46.38.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/f874fcac-2b4a-e842-e8b8-40534a30e778.jpeg)

ボタンをクリックするといちごが増えていることが確認できます。

![スクリーンショット 2022-10-15 8.46.59.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/39d43cb0-951a-1690-39dd-9f15c1e189b9.jpeg)

また、イチゴを追加する処理においてcopyを取ってる理由は下記の記事で詳しく解説しているので参考にしてみてください。

```js
  // イチゴを追加
  const addStrawberry = () => {
    fruits.push("いちご");
    setFruits(fruits); // => これだとstateが更新されない
  };
```
https://qiita.com/KNR109/items/744da4e3db51779da985

### 配列操作

配列を操作するメソットは``map``、``filter``、``find``、``reduce``などがありますが、今回は個人的にReact開発でよく使っている

- map
- filter

に絞って解説をしていきます。

#### map

> map() メソッドは、与えられた関数を配列のすべての要素に対して呼び出し、その結果からなる新しい配列を生成します。

**【各々の配列の値を2倍にする】**
```js
  const array = [1, 2, 3, 4];

  const new_array = array.map((i) => {
    return i * 2;
  });

  console.log(new_array); // => [2,4,6,8]
```

Reactにおいて``map``はJSX内でリストをループする際に使われることが多いです。

```jsx
  const [fruits, setFruits] = useState<string[]>([
    "りんご",
    "みかん",
    "ぶどう",
  ]);

  return (
    <>
      {fruits.map((fruit, index) => (
        <p key={index}>{fruit}</p>
      ))}
    </>
  );
```

![スクリーンショット 2022-10-15 9.34.12.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/5e055c45-8e21-8bf0-0447-dd1f6cdeabf6.jpeg)
他にもAPI等で受け取ったレスポンスデータから必要なデータのみを抽出する場合に使うこともあります。

```jsx
  // APIコール等のレスポンスデータ
  const responseDate = [
    { id: 1, name: "suzuki", age: 15 },
    { id: 2, name: "satou", age: 20 },
    { id: 3, name: "itou", age: 33 },
  ];

  // レスポンスデータからidとnameのみ抽出
  const result = responseDate.map((i) => {
    return {
      id: i.id,
      name: i.name,
    };
  });
```

![スクリーンショット 2022-10-15 9.38.06.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/d54283fa-75d9-f689-9b16-f1f9dc0218b5.jpeg)

#### filter

``filter``メソットは下記のように解説されています。

> filter() メソッドは、この配列の中から、提供された関数で実装されたテストに合格した要素のみを抽出したシャローコピーを作成します。

**【wordsの中から6文字より大きいのものだけを抽出】**
```js
  const words = [
    "spray",
    "limit",
    "elite",
    "exuberant",
    "destruction",
    "present",
  ];
  const result = words.filter((word) => word.length > 6);

  console.log(result);
```

``filter``に関しては検索処理やオブジェクト配列の中から条件に合ったものを抽出するときに利用されます。

**【usersの中から管理者権限(admin)を持つuserのみ抽出】**

```jsx
  const users = [
    {
      id: 1,
      name: "tanaka",
      admin: false,
    },
    {
      id: 2,
      name: "takahashi",
      admin: true,
    },
    {
      id: 3,
      name: "matuda",
      admin: false,
    },
    {
      id: 4,
      name: "okamoto",
      admin: true,
    },
  ];

  const admin_users = users.filter((i) => i.admin);

  console.log(admin_users);
```

![スクリーンショット 2022-10-15 10.29.40.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/31870e3d-de20-7883-713b-a7712487e9d7.jpeg)

### アロー関数

アロー関数はJavaScriptにおいて関数を作成する方法の一つです。

アロー関数の構文は下記のようになっています。
```js
(引数) => {
  // 処理
};
```

従来の関数をアロー関数に直してみます。
```js
// 従来の関数
function (a, b){
  return a + b + 100;
}
// アロー関数
(a, b) => a + b + 100;
```

アロー関数を使うメリットについては下記の記事で詳しく解説されているので、ぜひ参考にしてみてください。

https://qiita.com/10mi8o/items/2da84ab650f4caffdeea

### 非同期処理

非同期処理は[MDN](https://developer.mozilla.org/ja/docs/Learn/JavaScript/Asynchronous/Introducing#:~:text=%E9%9D%9E%E5%90%8C%E6%9C%9F%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%81%AF%E3%80%81%E9%95%B7%E3%81%8F%E7%B6%9A%E3%81%8F,%E7%B5%90%E6%9E%9C%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%97%E3%81%BE%E3%81%99%E3%80%82)では下記のように解説されています。

> 非同期プログラミングは、長く続く可能性のあるタスクを開始しても、そのタスクが完了するまで待つのではなく、そのタスクの実行中も他のイベントに応答できるようにする技術です。タスクが完了すると、プログラムはその結果を表示します。

具体例を用いて噛み砕いて解説をします。

**【同期処理(コードを書いた順番に処理が実行される)】**
```js
  let t = "初期値";
  console.log(t); // => "初期値"と出力
  t = "更新"; 
  console.log(t); // => "更新"と出力
```
同期処理ではコードを書いた順番で処理が実行されていることが確認できます。

![スクリーンショット 2022-10-18 20.59.21.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/1400addc-e21c-64ff-9e5a-78cf65f82784.jpeg)

**【非同期処理(コードを書いた順番に処理が実行されない)】**

```js
  let t = "0秒";
  console.log(t);
  setTimeout(() => {
    t = "2秒経過しました";
  }, 2000);
  console.log(t);
```

``setTimeout``内で2000ミリ秒(2秒)経過する前(処理を待たず)に次の``console.log(t)``の処理が発生しているのでどちらも"0"秒のままになっています。

![スクリーンショット 2022-10-18 21.01.26.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/dbdf6bc7-0361-18a6-7f4a-d2700df324fa.jpeg)

このように処理に待ち時間が発生し、かつ処理によって得られる値を利用したい場合、このままだと期待通りの結果を得ることができません。

下記を使うことで上記の処理を行うことができます。

- Promise
- async/await

#### Promise

Promiseは[MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise)では下記のように解説されています。

> Promise オブジェクトは、非同期処理の完了 (もしくは失敗) の結果およびその結果の値を表します。

具体的にコードで解説をしてきます。

- ``new Promise``でインスタンス化する
- インスタンスの中の引数にコールバック関数を渡す(非同期処理)
- ``resolve()``が呼ばれた後に``then``の中のコールバック処理が呼ばれる

```js
  let t = "0秒";
  console.log(t);
  new Promise((resolve) => {
    setTimeout(() => {
      t = "2秒";
      resolve(t);
    }, 2000);
  }).then((t) => {
    console.log(t);
  });
```

このように``setTimeout``の処理を待った後に``console.log(t)``が呼び出されているので期待通りの結果になっていることが確認できます。
![スクリーンショット 2022-10-18 21.16.35.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/2e182ae5-aef0-df9e-756c-5fc380a8d8ec.jpeg)

なお``Promise``についてのより詳しい解説はこの記事がわかりやすいので、より深堀したいという方は参考にしてみてください。

https://qiita.com/cheez921/items/41b744e4e002b966391a

#### async/await

``async/await``を利用することで``Promise``で書いた処理よりも簡潔に非同期処理を書くことができます。

``async/await``についてはMDNで下記のように解説されています。

> 非同期関数は async キーワードで宣言され、その中で await キーワードを使うことができます。 async および await キーワードを使用することで、プロミスベースの非同期の動作を、プロミスチェーンを明示的に構成する必要なく、よりすっきりとした方法で書くことができます。

- ``Promise``の中のコールバック関数をアロー関数として定義
- ``async``をアロー関数の前に付与
- ``await``を非同期処理の前に付与する
- 結果として入ってくる値を``result``に入れる

```js
  let t = "0秒";
  const timer = async () => {
    const result = await new Promise((resolve) => {
      setTimeout(() => {
        t = "2秒";
        resolve(t);
      }, 2000);
    });
    console.log(result);
  };
  timer();
```

これによって``then``を書かずに先ほどと同じ処理が行われていることが確認できます。

![スクリーンショット 2022-10-18 21.47.02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/cbb38263-0887-5809-e92d-63c61ba61cd6.jpeg)

``async/await``についてより詳しく知りたい人は下記の記事を参考にしてみてください。

https://qiita.com/soarflat/items/1a9613e023200bbebcb3

### APIコール

最後にJavaScriptの開発で必須項目でもあるAPI通信について解説をします。


#### クライアントとサーバー間のデータ通信について

まずクライアントサイドとサーバーサイドの通信について簡単に解説します。

1. クライアント(JavaScript等)からほしい情報をサーバーにリクエスト
2. サーバー(RubyやPHP等)はリクエストを受けデータをレスポンス
3. レスポンス(HTMLやJSON形式等)をクライアント側(画面)で表示

![ネタ系.001.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/062465ed-d8b4-0253-7adf-8af2a1abc89c.jpeg)

#### REST API

REST APIはリソースごとにURLのパスが準備されています。

リクエスト送信時のメソット(GET,POST,PUT,DLETE)を変えて同じリソースにリクエストを行うことで処理が実行されます。

![ネタ系1.001.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/18d9ed19-b979-12a5-ca0f-7f00291f2eb7.jpeg)

今回は先ほど紹介した下記の部分においてデータを実際に取得する処理を書いてきます。
![ネタ系12.001.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/1ccecbf2-a1ee-f857-accb-163ae30e663b.jpeg)

#### axiosを使ってAPIコール

APIコールをするためにJavaScriptでは``axios``というライブラリが用意されています。

``axios``を使うことで、GETやPOSTのHTTPリクエストを使ってサーバーからデータの取得、サーバーへデータ送信、追加、更新、削除を行うことができます。

[JSONPlaceholder](https://jsonplaceholder.typicode.com/)を使って具体的にデータを取得する処理を書いてみます。

**【JSONPlaceholderからusers情報をGETするリクエストを送る】**
```js
 const getUsers = async () => {
    const res = await axios.get("https://jsonplaceholder.typicode.com/users");
    console.log(res.data);
  };
  getUsers();
```

APIコールは外部との通信が走るので先ほど紹介した非同期処理の``async/await``を利用しています。

下記のように``users``情報が返ってきていることが確認できます。
![スクリーンショット 2022-10-19 9.34.16.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/74220ae8-b81e-0311-4a49-d3ea8f97cb81.jpeg)

またReactにおけるAPIコールは副作用なので``useEffect``内で呼び出されることが多いです。(``useAsync``等もある)

```jsx
  const [user, setUsers] = useState<User>([]);
  useEffect(() => {
    const getUsers = async () => {
      const res = await axios.get("https://jsonplaceholder.typicode.com/users");
      setUsers(res.data);
    };
    getUsers();
  }, []);

  console.log(user);
```

![スクリーンショット 2022-10-19 9.53.21.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/a32cd522-304e-4105-1137-e4a21280e386.jpeg)


なぜ``useEffect``の中で呼び出されるかについての詳しい解説は下記の記事でおこなっているので参考にしてみてください。

https://qiita.com/KNR109/items/e13a5c5b8b461e846902#useeffect%E3%81%AE%E5%BD%B9%E5%89%B2%E3%81%A8%E5%8B%95%E3%81%8D%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E6%95%99%E3%81%88%E3%81%A6%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84

## 最後に

いかがだったでしょうか。

今回はReactを学ぶ上で知っておくべきJavaScriptの基本概念についてまとめました。

他にもReact関連の記事を出しているので、合わせて読んでいただけると嬉しいです。

https://qiita.com/KNR109/items/e13a5c5b8b461e846902

https://qiita.com/KNR109/items/9f7ec8dd03d0bea8dc35