【React.js】useStateの使い方・どんなときに使うのかを解説
この記事では、Reactの基本的なフックである「useState」の詳しい使い方や実例、さらには類似のフック「useReducer」との違いや注意点について解説しています。
3行で要約すると
- 「useState」を用いてReactのコンポーネントの状態を効果的に管理する方法を解説
- 「useReducer」を使った複雑な状態管理と「useState」との主な違い、使い分け方を解説
- 「useState」の状態更新の際の非同期処理や複合データタイプの取り扱いの注意点を解説
「useState」の基本的な使い方
「useState」とは?
React.jsでコンポーネントの状態を管理するために使われるフックの一つがuseState
です。このフックを使うことで、Reactコンポーネントの状態を簡単に追加できるようになります。状態とは、例えばユーザーの入力やAPIからのデータなど、時間とともに変化するデータのことを指します。
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>現在のカウント: {count}</p>
<button onClick={() => setCount(count + 1)}>増加</button>
</div>
);
}
上記の例では、useState(0)
を使ってcount
という名前の状態を作成し、初期値を0
に設定しています。setCount
はこの状態を更新するための関数です。ボタンをクリックすると、カウントが増加します。
「useState」の使用例3パターン
入力フォームの値を管理する
useState
はユーザーからの入力を状態として管理するのにとても役立ちます。例えば、テキストボックスの入力を受け取る時、useState
を使うことでリアルタイムに値の変更を捉えることができます。
import React, { useState } from 'react';
function InputForm() {
const [inputValue, setInputValue] = useState('');
return (
<div>
<input
type="text"
value={inputValue}
onChange={e => setInputValue(e.target.value)}
/>
<p>入力されたテキスト: {inputValue}</p>
</div>
);
}
トグルスイッチの状態を管理する
トグルスイッチやチェックボックスのON/OFFの状態もuseState
で簡単に管理できます。
import React, { useState } from 'react';
function ToggleSwitch() {
const [isOn, setIsOn] = useState(false);
return (
<div>
<button onClick={() => setIsOn(!isOn)}>
{isOn ? 'ON' : 'OFF'}
</button>
</div>
);
}
リストの要素を追加・削除する
useState
を配列として使用することで、リストの要素の追加や削除も容易にできます。
import React, { useState } from 'react';
function TodoList() {
const [tasks, setTasks] = useState([]);
const [taskInput, setTaskInput] = useState('');
const addTask = () => {
if(taskInput) {
setTasks([...tasks, taskInput]);
setTaskInput('');
}
}
return (
<div>
<input
type="text"
value={taskInput}
onChange={e => setTaskInput(e.target.value)}
/>
<button onClick={addTask}>追加</button>
<ul>
{tasks.map(task => <li key={task}>{task}</li>)}
</ul>
</div>
);
}
この例では、タスクの入力と追加を行う簡単なTodoリストを作成しています。
「useState」と「useReducer」
「useReducer」とは?
useReducer
は、Reactのフックの一つで、より複雑な状態ロジックを扱うために使用されます。特に、前の状態から次の状態への遷移が複雑な場合や、関連するアクションが多い場合に有効です。useReducer
は、現在の状態とアクションを受け取り、新しい状態を返す純粋な関数(reducer)を使用して動作します。
import React, { useReducer } from 'react';
function counterReducer(state, action) {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
default:
throw new Error();
}
}
function CounterWithReducer() {
const [state, dispatch] = useReducer(counterReducer, { count: 0 });
return (
<div>
<p>カウント: {state.count}</p>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>増加</button>
<button onClick={() => dispatch({ type: 'DECREMENT' })}>減少</button>
</div>
);
}
「useState」と「useReducer」の違い
useState
は状態の変更ロジックが単純な場合に適しています。一方、useReducer
は複雑な状態遷移や関連するアクションが多い場合に役立ちます。具体的には、アクションに基づいて状態を変更することで、コードの見通しを良くすることができます。
// useStateを使った例
const [count, setCount] = useState(0);
setCount(count + 1);
// useReducerを使った例
const [state, dispatch] = useReducer(counterReducer, { count: 0 });
dispatch({ type: 'INCREMENT' });
useReducer
の大きな利点の一つは、状態の変更ロジックを外部のreducer関数に抽出できることです。これにより、ロジックの再利用やテストが容易になります。
「useState」を使用する際の注意点
初期値の設定に注意
useStateの初期値は、コンポーネントのレンダリング時に毎回計算されます。高価な計算が必要な場合、関数を使って遅延初期化をすることが推奨されます。
// 高価な計算を直接行うのではなく、関数で遅延初期化
const [value, setValue] = useState(() => {
const expensiveInitialValue = someExpensiveComputation();
return expensiveInitialValue;
});
非同期処理の扱い
useState
のセッター関数は非同期ではないので、直後に状態を参照すると、更新された値が反映されていないことがあります。このような場合、セッター関数に関数を渡すことで前の状態を元に新しい状態を設定することができます。
setCount(prevCount => prevCount + 1);
状態の更新の際の注意
useState
は浅い比較を行うため、オブジェクトや配列などの複合データタイプを更新する際は、新しいオブジェクトや配列を作成して更新する必要があります。
const [userInfo, setUserInfo] = useState({ name: 'Taro', age: 30 });
// 更新時は新しいオブジェクトを作成してセット
setUserInfo(prevInfo => ({ ...prevInfo, age: 31 }));
「useState」の使い方まとめ
useState
はReactのコンポーネントの状態を管理する基本的なフックです。状態の初期化、更新、参照などの操作がシンプルで直感的に行えます。ただし、状態の更新時の挙動や非同期処理、複合データタイプの更新には注意が必要です。適切な使い方を心がけることで、Reactアプリケーションの開発がよりスムーズに進められます。