はじめに
現在個人開発をしており、フロントエンドにReactを採用しております。まだ、開発途中ですがuseStateについて自分の頭の整理として執筆しました。
概要
開発内容は、ざっくりいうと上場している日本株の口数を入力し、運用期間毎に損益額を確認することができる。現在実装した要件を以下のとおり。
- 買いたい銘柄を検索することができる
- +,-ボタンを押せば、口数が増減する
- また、口数は入力もできる
- 口数に応じて合計金額が更新される
いずれもuseStateを使って実装しました。
useStateとは
Reactリファレンスには、『useState は、コンポーネントに state 変数 を追加するための React フックです。』とあります。
stateとは状態を管理するメモリです。
サービス内容によっては、ユーザー操作の結果として画面上の表示内容を変更する必要があります。
ショッピングサイトに例えると、商品名を入力したら該当する商品が一覧で掲示される、「購入」ボタンを押せば買い物カゴに追加される、といったものです。
そういった、ユーザーによる現在の入力値、買い物カゴの状態を「覚えておく」必要があります。Reactでは、こういったメモリをstateと呼んでいます。
そのため、useStateとは状態を管理するstateを追加するための機能です。
基本編
カウンターの状態を管理する事例を用いて、簡単に実装してみます。まず、全体版から。
目的: ボタンをクリックするたびにカウント値を増加させ、画面上に表示。
動作: 初期値としてカウントは0から始まり、ボタンをクリックするたびに1ずつ増加。
import { useState } from 'react';
const Counter = () => {
const [count, setCount] = useState(0); // 初期値0の状態を定義
const addcount = () => {
setCount(count + 1) //state変数に1を追加
}
return (
<div>
<p>現在のカウント: {count}</p>
<button onClick={addCount}>増やす</button>
</div>
);
};
const [count, setCount] = useState(0);
ここでは、useStateを呼び出して、state変数(今回の例ではcount)を宣言します。変数は慣習として、分割代入を利用して命名します。
useState(0)の(0)は、stateの初期値です。どんな型の値でも渡すことは可能で関数も渡すかことができます。
setCountは、countを更新するための関数です。例えば、setCount(1)を呼び出すと、状態countが[1]に更新されます。
<p>現在のカウント: {count}</p>
現在の値を画面に表示します。状態が更新されるたびにこの部分もサイレンダリングされ、新しい値が表示されます。
<button onClick={addCount}>増やす</button>
ここで、『増やす』ボタンを押下するとイベントハンドラが発火し、addCountのsetCount(count + 1)が実行されるため、countに1が追加されレンダリングされます。
以上より、
初期レンダリング時:
状態: count = 0
表示: 現在のカウント: 0
ボタンを1回クリック:setCount(0 + 1)が呼び出される。
状態: count = 1に更新。
表示: 現在のカウント: 1
ボタンをもう1回クリック:setCount(1 + 1)が呼び出される。
状態: count = 2に更新。
表示: 現在のカウント: 2
set 関数を呼び出した後に state 変数を読み取っても、呼び出し前の画面に表示されていた古い値が返されます。
const addcount = () => {
console.log(count); // 0
setCount(count + 1); //state変数に1を追加
console.log(count); //まだ0
setTimeout(() => {
console.log(count); //また0
},5000);
}
この変数は、読んだり書いたりできる普通の変数のように扱うことができなません。set関数内の更新は即時ではないことに注意が必要。
実装編
実際にuseStateを活用してアプリの機能へ応用してみました。
銘柄検索機能
ユーザーが検索欄に入力した文字列をリアルタイムで保持し、該当する銘柄をフィルタリングして表示。
const [filterName, setFilterName] = useState(''); //filterNameで管理
const companies = [{ name: '〇〇証券' },{ name: '〇〇商事' }];
const filteredCompanies = companies.filter((company) =>
company.name.includes(filterName)
);
return (
<div>
<h2>銘柄検索</h2>
<input
type="text"
placeholder="銘柄名前で検索"
value={filterName}
onChange={(e) => setFilterName(e.target.value)} //filterNameを更新
/>
<ul>
{filteredCompanies.map((company) => (
<li key={company.name}>{company.name}</li> //filterNamenに合致している銘柄を返す
))}
</ul>
</div>
);
口数の増減機能
+ボタンや-ボタンのクリックイベントで、現在の口数を状態として管理し、増減をリアルタイムで反映。
const [quantity, setQuantity] = useState(1);
const increaseQuantity = () => setQuantity(quantity + 1);
const decreaseQuantity = () => setQuantity(quantity > 0 ? quantity - 1 : 0);
口数の入力機能
入力欄に直接数値を入力できるようにし、その値を状態として保持。
const [quantity, setQuantity] = useState(1);
const handleInputChange = (e) => setQuantity(Number(e.target.value));
合計金額の更新機能
口数の状態が更新されるたびに、合計金額をリアルタイムで計算し表示。
const [quantity, setQuantity] = useState(1);
const [price, setPrice] = useState(1000);
const total = quantity * price;
最後に
今回のように、useStateを使うことで、ユーザー操作に応じて状態を管理し、動的なUIを簡単に構築できました。useStateをはじめ使用用途に応じてフックスを使い分け、引き続きスムーズなユーザー体験を提供できるよう心がけたいです。