[自分用]ニ◯・ロビン = 破壊的メソッド

## useStateで配列を使っていく
初期値の内容に応じて配列を作る。空配列でもOK！！
```jsx
export default function Home() {
  const [array, setArray] = useState([1,2,3]);

  return (
    <>
      <button onClick={handleAdd}>追加</button>
      <ul>
        {array.map((item) => {
          return <li key={item}>{item}</li>;
        })}
      </ul>
    </>
  )
}
```
ちなみに上記のコードでは[1]・[2]・[3]の三つが配列に加わり、`<li>`が三つ追加される。
```jsx
export default function Home() {
  const [array, setArray] = useState([]);
  
  const handleAdd = useCallback(() => {
    setArray((array) => {
      const newArray = [...array,1]
      return newArray;
    });
  },[])

  return (
    <>
      <button onClick={handleAdd}>追加</button>
      <ul>
        {array.map((item) => {
          return <li key={item}>{item}</li>;
        })}
      </ul>
    </>
  )
}
```
上記のコードでは「追加」を押したら、配列に「1」が追加されていく。
```jsx
setArray((array) => {
  const newArray = [...array,1]
  return newArray;
});
```
ここの部分を解説。
setArrayの中が関数になっているので、前回の配列情報を使える。
「追加」がクリックされるとその時の配列を認識(arrayのこと)し、「１」を追加した新しい配列を`newArray`に格納する。(破壊的であるpushを非破壊的に記述している。)
そして仕上げに`newArray`を`return`で返す。
※key(1)の被りでエラーが出ると思うが、実際の実装ではデータベースのID等を使うと思うので一旦無視

### 入力したテキストを配列に格納していきたい
```jsx
import { useCallback, useEffect, useState } from 'react';

export default function Home() {
  const [text , setText] = useState("");
  const [array, setArray] = useState([1,2,3]);

  {/* ここのtextに注目 */}
  const handleAdd = useCallback(() => {
    setArray((array) => {
      const newArray = [...array,text]
      return newArray;
    });
  },[text])

  return (
    <>
      <input type="text" value={text} onChange={e => {
        setText(e.target.value);
      }} />
      <button onClick={handleAdd}>追加</button>
      <ul>
        {array.map((item) => {
          return <li key={item}>{item}</li>;
        })}
      </ul>
    </>
  )
}
```
`handleAdd`関数部分の解説。
`text`はuseStateを使ったインプットタグの入力値。

引数のarrayで前回の配列を受け取り、その配列にtextを追加する。変更点は追加されたtextだけなので、新たにtextだけが追加される。

注意点は第二引数に[text]を書き忘れないこと！
何故ならコールバック関数を使っているため、textを変更したところでhandleAddは再レンダリングされない。一番初めに[1,2,3]を取得し、そのままになってしまう。

ちなみにsome(配列の中の少なくとも1つの要素が当てはまるかどうかを判定し、trueかfalseを返す)を使うと、二重登録を防ぐ事もできる！
`return array`を記述しないとその下の処理が実行されて、結局追加されてしまうので忘れないように！
```jsx
const handleAdd = useCallback(() => {
  setArray((array) => {
    if (array.some((item) => item === text)) {
      alert("既に存在しています");
      return array;
    }
    const newArray = [...array,text]
    return newArray;
  });
},[text])
```

## (非)破壊的メソッドとは
破壊的メソッドとは、元のデータ(今回だと配列)が変更されることをいう。
そのため変更前の配列を使用するために変数を指定しても、思っている結果と違うことがある。

それに比べて非破壊的メソッドとは、新しい配列を用意して作業することで、元のデータを保持することができる。

そこで役に立つのがスプレッド構文なのだが、改めて復習したいと思う。

## あらためてスプレッド構文のおさらい
```js
const arr = ['一つ目', '二つ目'];

console.log(arr);//['一つ目', '二つ目']
console.log(...arr);//一つ目 二つ目
```
arrをそのまま出力すると配列をそのまま出力され、...arr(スプレッド構文)を出力すると配列の中身が個別で出力される。
それを応用すると、要素を簡単に引数に入れることができる
```js
onst arr = [1, 2, 3, 4, 5];

const newArr = (num1, num2, num3, num4, num5) => {
  return num1 + num2 + num3 + num4 + num5;
};

console.log(newArr(arr[0], arr[1], arr[2], arr[3], arr[4]));//15
console.log(newArr(...arr));//15
```
同じ15が返るのに`console.log(newArr(...arr))`の方が圧倒的に楽！

### そしてここからが重要
配列をコピーしたい！！！
```js
//下記の配列を変数arr5に代入したい！
const arr = [1, 2, 3, 4, 5];

const arr5 = arr;
console.log(arr5);//[1, 2, 3, 4, 5]
```
無事arr5の中身が[1, 2, 3, 4, 5]になったのでめでたしめでたし！！**ではない。**
その理由が下記コード。
```js
arr5[0] = 800;
console.log(arr);//[800, 2, 3, 4, 5]
console.log(arr5);//[800, 2, 3, 4, 5]
```
あれ？arr5しか変更してないのに、arrまで変わってしまっている、、、

**（てかReactって状態が変更されないと再レンダリングされないじゃん？元の配列も一緒に変わったんなら、一生状態に変更がないから再レンダリングされないよね・・・。おもしろ・・・。
元の状態と差異を出すためにも、非破壊的メソッドを使って再レンダリングさせるのか。）**

そうつまり配列のコピーは「ニ○・ロビン」とようなものなのだ。
たくさん分身は出せるけど、そのダメージは何故か自分にかえってくる。

ということで**ニ○・ロビン = 非破壊的メソッド**という式が成り立つ。

### スプレッド構文を使って非破壊的メソッドにする

```js
const arr = [1, 2, 3, 4, 5];

//ここを少しかえる
const arr5 = [...arr];

arr5[0] = 800;
console.log(arr);//[1, 2, 3, 4, 5]
console.log(arr5);//[800, 2, 3, 4, 5]
```
よし！これで本当にめでたしめでたし！！
何故こうなったのかというと、`const arr5 = [...arr]`このように代入することで**コピーではなく新しい配列を作ることができる**からだ。
つまり**ニ○・ロビンのように見えてニ○・ロビンではない**ということだ。

## なぜ破壊的メソッドがダメなのか
これを理解するためには「ミュータブル(変更可能)・イミュータブル(変更不可能)」について知る必要がある。
簡単にいうと**一度値を作成した後に、その値を変更できるかどうか**ということ。

文字列や数値はデフォルトでイミュータブルになっている。
要は変数に何はアクションを与えたときに、参照元の変数(元の変数)に影響を与えないということ。
```js
let str = "Hello";
str.concat(" World"); // 新しい文字列 "Hello World" が生成されるが、str の値は変わらない

let num = 10;
num + 5; // 新しい数値 15 が生成されるが、num の値は変わらない
```
それに比べて配列とオブジェクトはデフォルトでミュータブルになっている。
(参考コードは「あらためてスプレッド構文のおさらい」にあるよ)

そのため配列とオブジェクトもイミュータブルとして扱うべく、破壊的メソッドを避けるような記述をするようになった。