0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

React完全入門ガイド ~ステートとイベントリスナ~

Last updated at Posted at 2025-10-01

参考教材

ステートとイベントリスナ

イベントに合わせて関数を実行しよう

イベントリスナとは
画面上でイベントが発生した際、実行する関数を登録する場所
イベントリスナに登録されたイベントハンドラによって処理できる

Reactにおけるイベントリスナの登録方法

const Example = () => {
  const clickHandler = () => {
    alert('クリックされました')
  }
  return (
    <>
      {/* onClick={}の{}の中に登録するのがイベントハンドラ */}
      <button onClick={clickHandler}>クリックしてね</button>
      <button>クリックしてね</button>
    </>
  );
};
{/*()を末尾につけると関数を実行した!ものを渡してしまう */}
<button onClick={clickHandler()}>クリックしてね</button>

→ クリックしてなくても関数が実行されてしまう

{/*イベントハンドラには関数を渡す */}
<button onClick={clickHandler}>クリックしてね</button>

※初心者は間違えやすいので注意

開発でよく利用するイベントタイプ

input要素とよく一緒に使うもの

<input
  type="text"
  
  // 入力値の変更を検知
  onChange={() => console.log("onChange検知")}
  
  // 入力欄からのフォーカスが消えたときのイベントを検知
  onBlur={() => console.log("onBlur検知")}
  
  // 入力欄がフォーカスを検知した時に発火するイベント
  onFocus={() => console.log("onFocus検知")}
/>

入力欄をフォーカスした 
2025-09-29 23.50の画像.jpeg

一度フォーカスして、フォーカスを外した
2025-09-29 23.53の画像.jpeg

入力欄に変更を加えた
2025-09-29 23.54の画像.jpeg

入力された値を取得

<input type="text" onChange={(e) => console.log(e.target.value)} />

2025-09-29 23.58の画像.jpeg

入力値が変更されるたびに、コールバック関数が呼ばれてコンソールに値が出力される

ホバーされたときのイベント

<div
  className="hover-event"
  onMouseEnter={() => console.log("カーソルが入ってきました。")}
  onMouseLeave={() => console.log("カーソルが出ていきました。")}
>

2025-09-30 0.01の画像.jpeg

追記

Reactの "onChage" イベントはJavaScriptの "onInput" のイベントと同じ意味
"onChage" はReactとJavaScriptで違う挙動をする

イベントに合わせて画面表示を更新しよう

useState

import { useState } from "react";

const Example = () => {
  let valAry = useState(0);
  return (
    <>
      <input
        //入力欄の作成
        type="text"
        //入力された値を取得
        onChange={(e) => {
          //値を変更する用の関数が格納
          const setFn = valAry[1];
          //変更したい値を中に入れる
          setFn(e.target.value);
        }
        } /> = {valAry[0]}
    </>
  );
};

uesStateが実行されたときに返す値は、読み込み用の値と変更用の関数が登録された関数

配列の0番目に参照用の値が渡ってくる
配列の0番目:参照用の値
配列の1番目:更新用の関数

2025-09-30 11.32の画像.jpeg

useStateを使うときは分割代入で使用する場合が多い

const Example = () => {
  let [val, setVal] = useState();
  return (
    <>
      <input
        type="text"
        onChange={(e) => {
          setVal(e.target.value);
        }
        } /> = {val}
    </>
  );
};

ステートとは?

画面が変更されるために必要な処理

・Reactにコンポーネントの再実行(再レンダリング)を依頼し、新しいReact要素を作成してもらう必要がある
・変更した値をどこかに保存しておく必要がある(Stateに保存)

これらを可能にする仕組みを提供するのがuseStateという関数

//コンポーネント(Example)を再レンダリング
const Example = () => {
  let [val, setVal] = useState();
  return (
    <>
      <input
        type="text"
        onChange={(e) => {
          //(e.target.value)に値を保存する必要がある
          //保持しておく場所を"State"という
          setVal(e.target.value);
        }
        } /> = {val}
    </>
  );
};

useStateの役割と使い方

①接続(Hook into)
Reactの内部と接続。状態が管理される

②"現在の値"と”更新関数”を返却

③更新関数で新しい値をReactに渡す。またReactに自身のコンポーネントを再レンダリングするよう依頼する

React内部に保持されたコンポーネントに紐づく値をstateという

state(状態)とは?

コンポーネント毎に保管・管理される値

ステート使用時の注意点①

const Example = () => {
//======================================================
  //useStateはコンポーネントのトップレベルでしか呼ぶことができない(カスタムフックも可)
  const [countA, setCountA] = useState(0);
  const [countB, setCountB] = useState(10);
  const [countC, setCountC] = useState(100);
//======================================================
  
  return (
    <>
      <p>ボタンを{countA}回押しました!</p>
      <button onClick={() => {
        setCountA(countA + 1)
      }}>ボタンA</button>

      <p>ボタンを{countB}回押しました!</p>
      <button onClick={() => {
        setCountB(countB + 1)
      }}>ボタンB</button>

      <p>ボタンを{countC}回押しました!</p>
      <button onClick={() => {
        setCountC(countC + 1)
      }}>ボタンC</button>
    </>
  )
};

2025-09-30 23.09の画像.jpeg

if文、for文、while文の中もuseStateは使えない

ステート使用時の注意点②

//カウントを増やしたり減らしたりするコード
const Example = () => {
  const [count, setCount] = useState(0);
  const countUP = () => {
    setCount(count + 1)
  };
  const countDown = () => {
    setCount(count - 1)
  };
  return (
    <>
      <p>現在のカウント: {count}</p>
      <button onClick={countUP}>+</button>
      <button onClick={countDown}>-</button>
    </>
  )
};

2025-09-30 23.25の画像.jpeg

一度に2ずつ増やしたい!

//NG
  const countUP = () => {
    //
    setCount(count + 1)
    setCount(count + 1)
  };

setCount(count + 1) は setCount(0 + 1) で setCount(1) という、setCountを1にしてください。という命令を2回書いているだけなので、+ ボタンを押しても1ずつしか増えない

//OK
  const countUP = () => {
    setCount(count + 1)
    //関数で記述する必要あり
    setCount( prevstate => prevstate + 1)
  };

prevstate に setCount(count + 1) の1が入っているので、+ボタンを押したら2になる
2025-09-30 23.33の画像.jpeg

オブジェクト型のステートを使う際の注意点

プリミティブ型
1, "str", bool, 10n, Symbol(), null, undefined

オブジェクト型
{}, []などのプリミティブ型以外

const Example = () => {
  const personObj = { name: "Tom", age: 18 };
  const [person, setPerson] = useState({ name: "Tom", age: 18 });
  const changeName = (e) => {
    //オブジェクトの形で渡す必要がある
    setPerson({name: e.target.value, age: person.age})
  };

  //オブジェクト型の値を更新するときは、更新するプロパティ以外のプロパティも設定する
  //age(年齢)を変更したいコードだけど、nameも記述している
  const changeAge = (e) => {
    setPerson({name: person.name, age: e.target.value})
  };

  //リセットボタン
  const reset = () => {
    setPerson({name: "", age: ""})
  };

  return (
    <>
      <h3>Name: {person.name}</h3>
      <h3>Age: {person.age}</h3>
      {/* valueで初期値を渡す */}
      <input type="text" value={person.name} onChange={changeName}/>
      <input type="number" value={person.age} onChange={changeAge}/>
      {/* 改行したいのでdivタグをつける */}
      <div>
        <button onClick={reset}>リセット</button>
      </div>
    </>
  )
};

初期値
2025-10-01 1.07の画像.jpeg

値を変更
2025-10-01 1.08の画像.jpeg

リセット後
2025-10-01 1.08の画像.jpeg

const changeName = (e) => {
  //オブジェクトリテラルで囲んだ場合、新しいオブジェクトが生成されるという意味になる
  setPerson({name: e.target.value, age: person.age})
};

オブジェクトの値を変更する場合、新しいオブジェクトを生成して、そのプロパティ(このコードでいうname)に新しい値を設定する操作が必要になる

スプレット演算子

今回の例はnameとageの2個だが、これが10個20個と増えたときにスプレット演算子を使用する

const changeName = (e) => {
  setPerson({...person, name: e.target.value})
};

スプレット演算子(...person)で元のオブジェクト({ name: "Tom", age: 18 })が展開されて、外側のオブジェクトリテラル({})で新しいオブジェクトが生成される。そして、上書きしたい値(name: e.target.value)を記述。複数でも可能。

※新しいオブジェクトを生成するのは初心者の頃によくハマりやすいトラップ

配列のステートを使う際の注意点

const Example = () => {
  const numArray = [1, 2, 3, 4, 5];
  const [ nums, setNums ] = useState(numArray);
  const shuffle = () => {
    //スプレッド演算子で新しい配列を作成
    const newNums = [ ...nums ];
    //.popで末尾の5を削除してvalueに入る
    const value = newNums.pop();
    //.unshiftで先頭に5を追加する
    newNums.unshift(value)
    setNums(newNums);
  };

  return (
    <>
      <h1>{nums}</h1>
      <button onClick={shuffle}>shuffle</button>
    </>
  );
};

shuffleボタンを押したら末尾の5が先頭になる

2025-10-01 17.29の画像.jpeg

配列もオブジェクトと同じように、スプレット演算子で新しい配列にしないとうまく動かないので注意

ステートとコンポーネントの関係

const Example = () => {
  //コンポーネントABを同じ場所に切り替えて置く場合
  const [ toggle, setToggle ] = useState(true);
  const toggleComponent = () => {
    //元の値と逆の真偽値を返す
    //trueが渡ってきたら!(NOT演算子)によってfalseになってリターンされる
    setToggle(prev => !prev) 
  };
  return (
    <>
      <button onClick={toggleComponent}>toggle</button>
      {/* 三項演算子を使い、trueならA、falseならBを表示 */}
      {toggle ?  <Count title="A" /> : <Count title="B" />}
    </>
  )
}

2025-10-01 17.58の画像.jpeg

コンポーネントAを値をあげて、コンポーネントBに移動すると、コンポーネントAの値を引き継ぐ
→ Reactはステートの値を引き継ぐ

コンポーネントAとコンポーネントBを分けて管理したい場合

key属性をつける

{toggle ?  <Count key="A" title="A" /> : <Count key="B" title="B" />}

keyはコンポーネントを識別するためにつける。keyによってコンポーネントの値もリセットされる

ステートを複数のコンポーネントで管理

const Example = () => {
  const [toggle, setToggle] = useState(true);
  
  //親コンポーネントに移動
  const [countA, setCountA] = useState(0);
  const [countB, setCountB] = useState(0);
  
  const toggleComponent = () => {
    setToggle(prev => !prev);
  }
  return (
    <>
      <button onClick={toggleComponent}>toggle</button>

      {/* props(count,setCount)を渡す */}
      {toggle ? 
      <Count key="A" title="A" count={countA} setCount={setCountA} /> : 
      <Count key="B" title="B" count={countB} setCount={setCountB} />}
      
    </> 
  )
}

//子コンポーネントにpropsを追加する
const Count = ({ title, count, setCount }) => {}

stateをpropsで渡すケース

・コンポーネントが消滅する可能性がある時
・特定のstateをコンポーネントで共有したいとき

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?