useStateを使う
useStateはコンポーネントに値を記憶させるHookです。現在値と更新関数を配列分割代入で受け取ります。
カウンターJSX
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<>
<p>現在: {count}</p>
<button onClick={() => setCount(current => current + 1)}>+1</button>
</>
);
}操作結果OUTPUT
現在: 0
クリック後: 現在: 1更新関数を呼ぶと、その場の変数が直ちに変わるのではなく、次のレンダーで新しい値が使われます。同じイベント内で前の値を何度も使うときは関数形式を使います。
イベント処理
JSXのonClickやonChangeへ関数を渡します。関数を実行した結果ではなく、後で呼ぶ関数そのものを渡す点に注意します。
クリックと入力JSX
function handleClick() {
console.log('クリックされました');
}
return (
<>
<button onClick={handleClick}>確認</button>
<input onChange={event => console.log(event.target.value)} />
</>
);onClick={handleClick}はクリック時に呼びますが、onClick={handleClick()}はレンダー中に実行してしまいます。イベントオブジェクトから入力値を読む場合はevent.target.valueを使います。
オブジェクトと配列を更新する
stateの配列やオブジェクトを直接変更せず、新しい配列・オブジェクトを作って更新します。
オブジェクトの更新JSX
import { useState } from 'react';
const [profile, setProfile] = useState({ name: 'Mika', age: 20 });
function birthday() {
setProfile(current => ({ ...current, age: current.age + 1 }));
}配列から削除JSX
function removeTodo(id) {
setTodos(current => current.filter(todo => todo.id !== id));
}スプレッド構文で元の値をコピーし、変更したい部分だけ置き換えます。直接profile.age++やtodos.push()をすると、Reactが変更を検知できない原因になります。
Stateを持ち上げる
複数の子コンポーネントが同じデータを使うときは、共通の親へstateを移し、propsで値と更新関数を渡します。
親がstateを管理するJSX
import { useState } from 'react';
function Input({ value, onChange }) {
return <input value={value} onChange={event => onChange(event.target.value)} />;
}
function Preview({ value }) { return <p>入力: {value}</p>; }
export default function App() {
const [text, setText] = useState('');
return <><Input value={text} onChange={setText} /><Preview value={text} /></>;
}stateの所有者を一か所に決めると、入力欄とプレビューが同じ値を表示できます。stateをどこへ置くかは、コンポーネント設計で最も重要な判断の一つです。
