Reactの基礎学習(refについて)

# 概要
Reactを勉強し始めたので、学習用＆記録用にまとめる(第3回)
[前回はpropについてまとめた](https://qiita.com/matsumotoSalmon/items/2de97933e4c75aa9748b)

# 学習に使用している本
https://wings.msn.to/index.php/-/A-03/978-4-8156-1948-0

# 先に：今回学んだことを置いておく
* stateとrefは全然違う
* 普通はstateを使うべき
* refは、値が変わったときに画面表示は更新されるわけではない

# 早速実践
* 今回は、[前々回](https://qiita.com/matsumotoSalmon/items/a01fcc9ecd341f970e3c)に作った画面を、refを使って作ってみます(結局stateも使っている)
* 「Reactアプリを生成」「index.htmlを編集する」はまたまた前回と同じなので省略

### 1. index.jsを書き換える(srcディレクトリの直下)
* 「Test3」というコンポーネントを呼ぶように変更しました
```react:index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import Test3 from './Test3';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <>
        <Test3 />
    </>
);
```

### 2. コンポーネントの作成

```react:Test3.js
import { useRef, useState } from 'react';

export default function Test3() {
    // A.stateを初期設定
    const name = useRef(null); // 非制御コンポーネント
    const country = useRef(null);
    const age = useRef(null);

    const [isEdit, setIsEdit] = useState(false);
    const [tmp, setTmp] = useState(0);

    // B.文字列変更時の処理
    const changeEvent = e => {
        setIsEdit(true);
        setTmp(tmp => tmp + 1);
    };

    // C.送信ボタン押下時の処理
    const sendEvent = () => {
        console.log(`コンソールログ 名前：${name.current.value} 出身：${country.current.value} 年齢：${age.current.value}`);
    }

    // D.画面表示
    return (
        <form>
            <div>
                <label htmlFor='name'>おなまえ：</label>
                <input id='name' name='name' type='text' ref={name} defaultValue="あきら" onChange={changeEvent} />
            </div>
            <div>
                <label htmlFor='age'>ねんれい：</label>
                <input id='age' name='age' type='number' ref={age} defaultValue={18} onChange={changeEvent} />
            </div>
            <div>
                <label htmlFor='country'>しゅっしん：</label>
                <input id='country' name='country' type='text' ref={country} defaultValue="日本" onChange={changeEvent} />
            </div>
            { isEdit &&
                <div>
                    <button type="button" onClick={sendEvent}>そうしん！</button>
                </div>
            }
            
            { isEdit &&<p temp-data={tmp}>
                {(country.current.value === '日本' || country.current.value === '東京') && 'ご近所の'}
                {(country.current.value !== '日本' && country.current.value !== '東京') && country.current.value + 'からはるばるやってきた'}
                {name.current.value}さん ( {age.current.value}歳 ) ！よろしく！
            </p>}
        </form>
    )
}
```
### 3. 実行！
```
$ cd {アプリを生成したディレクトリ}/test
$ npm start
```

### 4.結果
* refについて勘違いしていたので、テキスト表示は無理やり出しています。
▼ 初期表示
![スクリーンショット 2024-06-10 214821.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1719849/3ee06afe-1947-520e-a39c-720aa47a35be.png)


▼ 入力変更
![スクリーンショット 2024-06-10 220636.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1719849/4685cc10-837c-4fac-b73e-d82e0419aab6.png)

### 5. 「3.コンポーネントの作成」について
#### まず.refとは
* コンポーネントが生成されてから破棄されるまで維持される、変更可能なオブジェクト とのこと(参照まま)
* 注意なのが、stateと違って値が変わったときに画面表示は更新されるわけではないということ
* ↑よって、今回はテキスト表示を結局stateを使って出しています。。。

#### A.stateを初期設定
* refを使うときの定型文で、useRef(null)で初期化しています
* isEdit と tmp は state です

#### B.文字列変更時の処理
* 画面で文字入力を変更したときに呼び出している関数(onChangeで呼び出している)
* A.で定義したstateの変数を更新している
    * isEditのほうは表示非表示の制御
    * tmpのほうは入力変更時にテキストも更新されるように無理やりおいているにすぎません

#### C: 送信ボタン押下時の処理
* 送信ボタン押下時(onClick)に呼び出している関数
* Dも同じですが、値の取得は`{refの変数}.current.{要素の属性}`で取得できます

#### D: 画面表示
* 「おなまえ」「ねんれい」「しゅっしん」の入力のタイプはそれぞれ異なるが、構成はおなじ
    * `<label>`は項目名表示
    * `<input>`は入力欄
        * ref：refの変数と要素を紐づけるための記述
        * defaultValue：初期値の設定。valueに値を設定すると入力変更できなくなるので注意
        * id、name：今回はただ設定しているのみ
        * type：入力欄のタイプ。おなまえとしゅっしんはもじにゅうりょくで、ねんれいは数値になっている
        * onChange：入力変更時に呼び出す関数(B.)を設定
 * `{ form.isEdit && ~~~ }`は、表示非表示制御
    * isEditは初期値はfalseなので`<div>~~</div>`が表示されないが、一度でも入力が変更されればB.によってtrueになるので表示される仕組みにしている
* 一番最後の`<p temp-data={tmp}>～</p>`は、入力値でリアルタイムに変更されるテキスト表示
    * B.で数字が1ずつ足されている「tmp」を置くことで、文字入力の度に文字表示が更新される仕組み