React、Next.jsの現場で1番使うuseStateとuseEffect! これを知らないと現場でヤバい!
useStateとuseEffectは実務でめっちゃ使う!
自分は今Next.jsを使った現場では2ヶ月目です。
現場で詰まっていた時にuseStateやuseEffectのことが理解できていないことが原因で、
エラーで詰まってしまいました。そんな時にベテランエンジニアの方から
useStateとuseEffectは実務でよく使う
からこの2つの理解だでは
ちゃんとやるようにアドバイスをもらいました。
他にも
useState、useEffect、useContext、useReducer、useRef、useCallBack、useMemo
とか色々ありますが、まずはなの2つを理解することが先です。。
useStateとはどんな時に使う?
useStateはウェブサイトやアプリのページで、そのページがどんな情報があるのか管理する道具みたいなものです。SNSを例に出していきましょう!
例1
例えばSNSとかで投稿したりしますよね。
ここで何件投稿したかをメモするとします。このメモがuseStateの役割です。
1.メモの作成
まず、投稿数を書き込むメモ(メモがuseState)を用意します。
メモは初めに0と書きます。これが初期値
です。
2.投稿数の変更
投稿数が変わるたびに、メモに新しい数を書きます。
例えば、1投稿するたびに、メモの投稿数を1ずつ増やし、今何件投稿されたかわかります。
3.投稿数の読み取り
ウェブページ上には、メモに書かれた投稿数が表示され、ユーザーがページを見ると投稿数を確認できます。
ユーザーが何か投稿すると、メモの数が増え、それがウェブページに表示されます。
つまりuseStateはReactコンポーネントが情報を保持し、
その情報を表示したり変更したりするのに使われます。
他にもフォームの入力など、ウェブページ上で何かを追跡して表示したい時に使います。
これらの投稿を管理するために、useStateを使用できます。
例2
SNSユーザーが投稿したメッセージや写真を表示する機能があります。
これらの投稿を管理する時にもuseStateを使用できます。
1.投稿のメモの作成
最初に、SNSが表示する投稿したものをメモ(メモがuseState)しておきます。
初めには何も投稿がないため、メモは空白です。
2.新しい投稿の追加
ユーザーが新しいメッセージや写真を投稿すると、メモにその新しい投稿が追加されます。
これにより、ウェブページに新しく投稿した写真などが表示されます。
3.投稿の表示
ウェブページ上には、メモに書かれた投稿が表示され、ユーザーは他人の投稿を見ることができます。
他にもコメントやいいねも管理できます。各投稿のコメントやいいねもuseStateを使って管理できます。
useStateは、SNSでユーザーが投稿した情報や他のユーザーとのやり取りを管理するために非常に便利です。
新しい投稿を追加し、コメントやいいねを追跡し、それに基づいてウェブページを更新するのに使われています。
このuseStateが使われて自分たちはいいね数が見れたりするんですね。
画像で確認
実際に画像で確認してましょう!
useStateでカウント機能
簡単なカウント機能を作成します。
useState(0)などは初期値です。<></>
はfragmentです。
import {useState} from "react";//useStateをインポート
const Practice = () => {
const [count1,countSet1] = useState(0);//初期値
const [count2,countSet2] = useState(10);//初期値
const [count3,countSet3] = useState(100);//初期値
return(
<>//fragment
<p>ボタン1を{count1}回</p>
<button onClick={() =>{
countSet1(count1 + 1);
}}>ボタン1</button>
<p>ボタン2を{count2}回</p>
<button onClick={() =>{
countSet2(count2 + 10);
}}>ボタン2</button>
<p>ボタン3を{count3}回</p>
<button onClick={() =>{
countSet3(count3 + 100);
}}>ボタン3</button>
</>
)
};
export default Practice;
これはボタン1を1クリックで1カウント増えていき、ボタン2を1クリックで10カウント増えていき、ボタン100を1クリックで100カウント増えていく機能です。
useStateを実務で使ったケース
自分は実際に実務ではユーザーのとあるデータの件数を画面上に出力させたいと思って
useStateを使って実装しました。しかし、0件のままでした。
理由はまだバックエンドが実装されていなかったのでAPIの連携ができていないので
ダミーデータを表示させていました。つまり表示は変わりません。
このように表示が変わらないダミーデータがある段階での実装では意味がありませんでした。
これだと0件でしたが、
const List: React.FC<Props> = () => {
const [playerCount] = useState(players.length);
const List: React.FC<Props> = ({ players }: Props) => {
return (
<div>
<div style={{ width: "90%", textAlign: "center"}}>
{playerCount}人の選手
以下にしたら件数が出てきました。
const List: React.FC<Props> = ({ players } }: Props) => {
return (
<div>
<div style={{ width: "90%", textAlign: "center" }}>
{players.length}人の選手
</div>
⚫︎補足
実際に実装したものとはコードは変えています。
useEffect
useEffectはウェブページ上で特定のアクションに対する反応を定義します。
そのアクションによって何かを行うためのツールみたいなものです。
ex)
SNSで例えると、写真やメッセージなどをSNSでは共有したりします。
その中でも、useEffectは、SNSのウェブページを更新するのに使われる特別な道具です。
1.新しい投稿を表示
TwitterなどでuseEffectを使って、新しい投稿がSNSのウェブページに表示されるようにします。写真を投稿したり、ツイートを投稿するたびに、それらがウェブページに自動的に現れます。
2.新しい通知を受け取る
新しい投稿や通知があると、useEffectを使って教えてくれます。
例えば、新しい友達リクエスト、自分のツイートのいいね、誰かが自分の投稿にコメントしたときに通知が表示されます。
3.アクションに対する反応
ボタンをクリックすると、useEffectを使って何か特別なことを行うこともできます。
例えば、友達の投稿に「いいね」を押すと、それがウェブページ上に表示されます。
つまりuseEffectはSNSのウェブページが友達やフォロワーとのコミュニケーションや最新の情報をリアルタイムで表示するのに使われる特別な道具です。新しい情報があれば、自動的に更新され、自分のアクションによって反応します。
他にも例を出してみます。
ex)
ウェブページ上で時に現在の時間を確認するために時計を表示したい、useEffectを使います。
1.時計の表示
useEffectを使って、ウェブページが読み込まれたら(または特定の状況が発生したら)時計を表示します。
2.自動更新
useEffectを使えば、時計は自動的に更新され、毎秒、現在の時間を表示します。
3.アクションへの反応
ボタンをクリックすると、useEffectを使って何か特別なことを実行することもできます。
例えば、ボタンをクリックしたときに、メッセージを表示することができます。
簡単に言えば、useEffectはウェブページ上で特定のアクションに対する反応を定義するのに使います。
何か特別なことをしたいときに、そのアクションに応じて何かを行うためのツールとして考えてください。
useEffectはカスタムフックか
useEffectはカスタムフックではなく、Reactフックの一つで、Reactの中にある、
特別な機能の一つです。
これはコンポーネントが読み込まれたり再レンダリングされたりする時に特定の動作を実行するために使います。
カスタムフックとは、開発者が自分で作成した小さなツールみたいなもので、
開発者が特定のタスクや機能を再利用できるようにまとめたもので、通常、コードの共有や整理できます。
ex)
テーマを切り替える機能を提供するカスタムフックを作成することができ、
テーマの状態を管理し、
テーマを切り替えるための関数を提供します。
このようにして、テーマ切り替え機能をアプリケーションのどのコンポーネントからでも簡単に使用できます。
要はuseEffectはReactの一部で、特定のタイミングで動作を実行するためのツールで、
カスタムフックは開発者が自分で作成し、コードを整理し、再利用するための小さなツールです。
useEffectの使用例
関数の実行タイミングをReactのレンダリング後まで遅らせるhookです。
副作用の処理を関数コンポーネントで扱えます。
副作用とは、データの取得、DOMの更新、アニメーションの開始、イベントリスナーの追加など、コンポーネントのレンダリングに直接関係のない処理です。
import { useState,useEffect } from "react";
const Practice = () => {
const [time,setTime] = useState(0);//useState フックを使用して、 time という状態変数を宣言し、初期値を 0
useEffect(()=>{
window.setInterval(()=>{
setTime(prev => prev+1);
},1000);
},[])//seEffect フックに渡された第2引数が空の配列 [] であるため、 useEffect フックは、コンポーネントが初めてマウントされたときに一度だけ実行
return(
<h2>
<time>{time}</time>
<span>秒経過</span>
</h2>
);
};
export default Practice;
useEffect
を使って、コンポーネントが初めてマウントされたときに一度だけ実行されるタイマーをセットアップします。このタイマーは、1秒ごとにtimeの状態を更新することで、経過時間を測ります。
スタートなどのボタンはここでは紹介していません。
実務での使用例
実際は違うのですが、選手情報の一覧取得の方法です。
import { useState, useEffect } from "react";
import axios from "axios";
export default function useFetchPlayersData() {
const [playersData, setPlayersData] = useState([]);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await axios.get("/api/players"); // 選手情報を取得するAPIエンドポイントに変更
setPlayersData(response.data);
} catch (error) {
setError(error);
}
};
fetchData();
}, []);
return { playersData, error };
}
useContext(おまけ)
useContextは、Reactで使われるツールで、
アプリ内の異なる部分でデータや設定の情報を共有するのに使います。
ex)
友達とお寿司のネタの種類を共有するアプリを使っているとします。
各友達は好きなお寿司の種類を設定できます。
useContextを使うと、友達が設定したお寿司の種類を異なる部分で共有できます。
1.設定
最初に、お寿司の種類を保存する***「コンテキスト」を設定***します。
これは自分と友達の好きなお寿司のネタリストです。
2.提供
あなたの友達は、それぞれ自分の好きなお寿司のネタを設定します。
この情報はコンテキストに提供されます。
3.利用
あなたや他の友達は、useContextを使ってコンテキストから好きなお寿司のリストを読み取ることができ、
誰がどんなお寿司が好きなのかを共有できます。
簡単に言えば、useContextは友達間で好きなお寿司のネタの情報を共有するための方法です。
アプリケーション内でデータや設定を共有するときに役立つツールです。
参考資料
1.ChatGPTにも相談しました。
2.useStateはこの資料も参考にしてください。
3.useEffectはこの記事を参考にしてください。
Discussion
失礼します。
その通りで、他のステートから求められるような値は、実は useState を使わずに Props ・他のステートなどから直接計算するのが適切です。
useState はむしろ、親から渡された値が変わっても変わらない値に使います。
ちなみに、ステートは親にあり、子は Props を受け取るだけ のパターンを Lift State Up, そのような子コンポーネントのことを Controlled Component と呼びます。
▼ 新ドキュメントには、このように複数のコンポーネント間の連携もふくめた、実装のベストプラクティスが書かれているので是非ご参考になさってください。
有益なコメントありがとうございます。