stock.dev
Next.jsの勉強会 vol.4 useState

Next.jsの勉強会 vol.4 useState

·5 min read

Next.js App Routerではページやコンポーネントは基本的にServer Componentとして扱われる。

しかし、ボタンをクリックして表示を切り替えるような UI では、ブラウザ上で状態を持つ必要があるため、Client ComponentとuseStateを使用する。

Server ComponentとClient Component

Next.js App Routerでは、何も指定しないコンポーネントは基本的にServer Componentになる。

Server Componentとは、サーバー側でHTMLを作るコンポーネント。

一方で、ユーザー操作や状態管理を扱う場合はブラウザ側で動く必要があるので、Client Componentを使用する。 下記のような場合↓

onClick={() => ...}
useState(...)

"use client"とは

ファイルの先頭に"use client"を書くと、Client Componentとして扱われる。

"use client";

今回作ったコンポーネントでは、useStateonClickを使うため、ファイルの先頭に "use client"を書いた。

"use client";
 
import { useState } from "react";

"use client" は、コンポーネントの中でユーザー操作やstateを扱うための合図。

useStateとは

useState は、React で「変化する値」を持つための機能。

今回の例では、詳細文を開いているかどうかをisOpenというstateで管理した。

const [isOpen, setIsOpen] = useState<boolean>(false);

このコードの意味↓

isOpen
現在の状態
 
setIsOpen
状態を変更するための関数
 
useState<boolean>(false)
最初の値は false、型は boolean

setIsOpenは自分で作る関数ではない

setIsOpenは、自分で定義した関数ではなく、useStateが自動で用意してくれる、stateを更新するための関数のこと。

const [isOpen, setIsOpen] = useState<boolean>(false);

useState は、2つの値を返します。

1つ目: 現在の値
2つ目: その値を変更する関数

名前は自由に付けられるが、Reactでは次のような命名が一般的。

const [count, setCount] = useState<number>(0);
const [name, setName] = useState<string>("");
const [isOpen, setIsOpen] = useState<boolean>(false);

state名setState名の形にすると、読みやすくなる。

useState<boolean>の意味

useState<boolean>は、このstateがboolean型であることを明示している。

const [isOpen, setIsOpen] = useState<boolean>(false);

つまり、isOpenにはtrueまたはfalseだけが入る。

今回のように初期値がfalseの場合、TypeScriptは自動でbooleanと推論できるので、実務では次のように書いても動く。

const [isOpen, setIsOpen] = useState(false);

ただし、学習中はuseState<boolean>のように明示すると、stateの型を意識しやすくなる。

ボタンで状態を切り替える

ボタンを押したときにisOpenの値を反転させた。

onClick={() => setIsOpen(!isOpen)}

!isOpenはbooleanの反転。

false -> true
true -> false

そのため、ボタンを押すたびに開く・閉じるが切り替わる。

表示を切り替える

ボタンの文字は、三項演算子を使ってisOpenの値によって切り替える。

{isOpen ? "閉じる" : "詳細を見る"}
isOpen が true なら「閉じる」
isOpen が false なら「詳細を見る」

詳細文は、isOpenがtrueのときだけ表示。&&を使うと条件がtrueのときだけJSXを表示する。

{isOpen && (
  <p className="mt-4 text-zinc-300">
    初回相談では、目的、必要なページ、公開希望時期を一緒に整理します。
  </p>
)}

ページ全体をClient Componentにしない

今回、useStateを使うのはContactToggleのみ。

そのため、トップページ全体に"use client"を書くのではなく、ContactToggleだけを Client Componentにした。

import { ContactToggle } from "./contact-toggle";
<ContactToggle />

このように、ユーザー操作が必要な小さな部品だけをClient Componentにすると、ページ全体は Server Componentのまま保てる。