参考教材
ステートとイベントリスナ
イベントに合わせて関数を実行しよう
イベントリスナとは
画面上でイベントが発生した際、実行する関数を登録する場所
イベントリスナに登録されたイベントハンドラによって処理できる
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検知")}
/>
入力された値を取得
<input type="text" onChange={(e) => console.log(e.target.value)} />
入力値が変更されるたびに、コールバック関数が呼ばれてコンソールに値が出力される
ホバーされたときのイベント
<div
className="hover-event"
onMouseEnter={() => console.log("カーソルが入ってきました。")}
onMouseLeave={() => console.log("カーソルが出ていきました。")}
>
追記
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番目:更新用の関数
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>
</>
)
};
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>
</>
)
};
一度に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になる

オブジェクト型のステートを使う際の注意点
プリミティブ型
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>
</>
)
};
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が先頭になる
配列もオブジェクトと同じように、スプレット演算子で新しい配列にしないとうまく動かないので注意
ステートとコンポーネントの関係
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" />}
</>
)
}
コンポーネント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をコンポーネントで共有したいとき












