はじめに
前回は、予定データをコンポーネントに分割し、propsで受け渡して一覧表示するところまで作った。ただし、表示していたのはコード内に直接書いた固定のデータだった。
今回は、いよいよReactの中心的な機能であるuseStateを使い、画面上から予定を追加・削除できるようにする。ここまでできると、ようやく「アプリらしい」動きになってくる。
今回やること
useStateを使って、予定の配列を状態(state)として管理する- 入力フォームから新しい予定を追加する
- 一覧から特定の予定を削除する
今回もツールが生成したpackage.jsonなどのファイルは変更していない。読むべきは、この後出てくるApp.jsxとcomponents/配下の2ファイルだけである(詳しくは第1回を参照)。
useStateとは
useStateは、コンポーネントの中に「変化する値」を持たせるためのReactの機能(Hook)である。
src/App.jsx(抜粋)
const [schedules, setSchedules] = useState(initialSchedules)
schedules:現在の予定一覧(値そのもの)setSchedules:予定一覧を更新するための関数initialSchedules:最初に表示しておく初期値
Ver.2までは、schedulesをただの定数として扱っていたが、useStateで管理することで、「値が変わったら画面も自動的に再描画される」という仕組みが手に入る。
予定を追加する
追加処理は、既存の配列に新しい要素を足した「新しい配列」を作り、それで置き換える形で行う。
src/App.jsx(抜粋)
const handleAdd = ({ date, title }) => {
const newSchedule = { id: nextId, date, title }
nextId += 1
setSchedules((prev) => [...prev, newSchedule])
}
[...prev, newSchedule]という書き方(スプレッド構文)がポイントである。prev(今までの配列)の中身をすべて展開したうえで、末尾にnewScheduleを加えた新しい配列を作っている。
Reactでは、配列や状態を直接書き換えるのではなく、「新しいものを作って置き換える」という考え方が基本になる。この点は最初つまずきやすいので、意識しておくとよい。
予定を削除する
削除は.filter()を使い、「消したいid以外」を残した新しい配列を作る。
src/App.jsx(抜粋)
const handleDelete = (id) => {
setSchedules((prev) => prev.filter((schedule) => schedule.id !== id))
}
入力フォームを作る
フォーム自体にも、入力中の値を保持するためのuseStateを使う。
src/components/ScheduleForm.jsx
function ScheduleForm({ onAdd }) {
const [date, setDate] = useState('')
const [title, setTitle] = useState('')
const handleSubmit = (event) => {
event.preventDefault()
if (!date || !title) return
onAdd({ date, title })
setDate('')
setTitle('')
}
return (
<form className="schedule-form" onSubmit={handleSubmit}>
<input type="date" value={date} onChange={(event) => setDate(event.target.value)} />
<input
type="text"
value={title}
onChange={(event) => setTitle(event.target.value)}
placeholder="予定のタイトル"
/>
<button type="submit">追加</button>
</form>
)
}
フォームの送信時(handleSubmit)に親から渡されたonAddを呼び出し、実際の追加処理はApp側に任せている。送信後はsetDate('') setTitle('')で入力欄を空に戻している。
削除ボタンをコンポーネントに追加する
Ver.2のScheduleItemに、削除ボタンとonDeletepropsを追加した。
src/components/ScheduleItem.jsx
function ScheduleItem({ title, date, onDelete }) {
return (
<li className="schedule-item">
<span className="schedule-item__date">{date}</span>
<span className="schedule-item__title">{title}</span>
<button type="button" onClick={onDelete}>削除</button>
</li>
)
}
呼び出す側(App.jsx)では、どのidを削除するかをその場で指定した関数を渡している。
src/App.jsx(抜粋)
<ScheduleItem
key={schedule.id}
title={schedule.title}
date={schedule.date}
onDelete={() => handleDelete(schedule.id)}
/>
実行結果
npm run devで開発サーバーを起動し、ブラウザで確認する。終了する場合はターミナル上でCtrl + Cを押す(Ctrl + Zは一時停止するだけなので使わない)。



日付とタイトルを入力して「追加」を押すと一覧に加わり、各行の「削除」ボタンを押すとその予定が消える。
今回のまとめ
useStateで配列を状態として管理すると、値の変化に応じて画面が自動的に再描画される- 追加はスプレッド構文、削除は
.filter()で「新しい配列を作って置き換える」のがReact流のやり方 - フォームの入力値も
useStateで管理する
ただし、現状ではブラウザを再読み込みすると、追加した予定は消えてしまう。次回はuseEffectとlocalStorageを使い、データをブラウザに保存して再読み込みしても消えないようにする。
ソースコード
今回のソースコードは、私のGitHubで公開している。以下のリンクを参照していたただきたい。
GitHub:https://github.com/HappyTalk10/pc-labo-react-learning/tree/main/03_usestate-todo




コメント