今回やること
前回は、Reactを動かしてJSXを表示しました。
今回は、アプリに一覧・新規登録・編集の3画面がある状態を作り、
screen Stateで表示を切り替えます。
公開日:更新日:
前回は、Reactを動かしてJSXを表示しました。
今回は、アプリに一覧・新規登録・編集の3画面がある状態を作り、
screen Stateで表示を切り替えます。
この段階では、各画面の中身はまだ作りません。 画面名を表示し、切り替わったことだけ確認します。
今回から実際のアプリ画面を作っていくため、画面全体をmainで囲みます。
また、アプリのタイトルやボタンを置く部分はheaderで囲んでおきます。
それでは、次のようにApp.jsxを書き換えてみましょう。
第2回で用意したCSSを画面に適用するため、JSXにclassNameを追加します。
JSXでは、HTMLのclassの代わりにclassNameでCSSクラスを指定します。
複数の操作ボタンはheader-actionsというwrapperにまとめます。
export default function App() {
return (
<main className="list-screen">
<header className="list-header">
<h1>気になるものリスト</h1>
<div className="header-actions">
<button type="button">新規登録</button>
<button type="button">編集</button>
</div>
</header>
<h2 className="screen-title">一覧画面</h2>
</main>
);
}
次のような画面になればOKです。
現在はボタンを置いただけなので、クリックしても表示は変わりません。
ボタンをクリックしたときに画面を切り替えるには、 「現在どの画面を表示しているか」をReactに覚えておいてもらう 必要があります。
Reactでは、画面の表示に使う 変化する値を管理する仕組みをState(ステート) と呼びます。
今回のアプリでは、「一覧画面」「新規登録画面」「編集画面」の どの画面を表示しているかによって、ブラウザに表示する内容が変わります。
そこで、現在表示している画面を表す値をStateとして管理します。
今回は、次の3つの文字列を使って画面を表します。
| 値 | 表す画面 |
|---|---|
"list" |
一覧画面 |
"create" |
新規登録画面 |
"edit" |
編集画面 |
たとえば、現在の値が"list"なら一覧画面を表示し、
"create"なら新規登録画面を表示する、という使い方をします。
Stateを用意するには、ReactのuseStateを使います。
まず、App.jsxの先頭でuseStateを読み込みます。
import { useState } from "react";
次に、Appの中で次のように書きます。
export default function App() {
const [screen, setScreen] = useState("list");
// このあと画面の表示を切り替えます
}
今回のポイントは、次の1行です。
const [screen, setScreen] = useState("list");
今回は、現在表示している画面を管理するStateを
screen Stateと呼ぶことにします。
このうち、screenは現在の値を保持する
state変数、
setScreenはStateを更新するための
更新関数です。
更新関数には、setScreenのように
「set + state変数名」という名前を付けるのが一般的です。
それぞれの部分を分けて見てみましょう。
| 部分 | 役割 |
|---|---|
useState("list") |
初期値を"list"としてStateを用意する |
screen |
現在の値を保持するstate変数 |
setScreen |
Stateを更新するための更新関数 |
"list" |
Stateの初期値 |
アプリを最初に表示したときは、
screenの値が"list"になります。
screen
↓
"list"
Stateの値を変更するときは、
先ほど用意した更新関数setScreenを使います。
たとえば、次のように書きます。
setScreen("create");
これを実行すると、state変数screenの値が
"create"へ変わります。
screen
"list"
↓
setScreen("create")
↓
"create"
同じように、setScreen("edit")とすれば編集画面を表す値に、
setScreen("list")とすれば一覧画面を表す値に変更できます。
このstate変数screenの値を使って、
次に表示する画面を切り替えてみましょう。
if文でstate変数screenの値を条件にして、
表示するJSXを切り替えます。
import { useState } from "react";
export default function App() {
const [screen, setScreen] = useState("list");
if (screen === "create") {
return (
<main className="form-screen">
<header className="screen-header">
<h1>気になるものリスト</h1>
<div className="header-actions">
<button type="button" className="secondary" onClick={() => setScreen("list")}>
一覧へ
</button>
</div>
</header>
<h2 className="screen-title">新規登録画面</h2>
</main>
);
}
if (screen === "edit") {
return (
<main className="form-screen">
<header className="screen-header">
<h1>気になるものリスト</h1>
<div className="header-actions">
<button type="button" className="secondary" onClick={() => setScreen("list")}>
一覧へ
</button>
</div>
</header>
<h2 className="screen-title edit-title">編集画面</h2>
</main>
);
}
return (
<main className="list-screen">
<header className="list-header">
<h1>気になるものリスト</h1>
<div className="header-actions">
<button type="button" onClick={() => setScreen("create")}>
新規登録
</button>
<button type="button" onClick={() => setScreen("edit")}>
編集
</button>
</div>
</header>
<h2 className="screen-title">一覧画面</h2>
</main>
);
}
今回は、state変数screenの値が"create"なら新規登録画面、
"edit"なら編集画面を表示します。
どちらにも当てはまらない場合は、最後のreturnで一覧画面を表示します。
一覧画面を基本の画面として扱うため、最後のreturnにしています。
一覧画面の「新規登録」ボタンをクリックすると、次の部分が実行されます。
onClick={() => setScreen("create")}
setScreen("create")によって
state変数screenの値が"create"になるため、
次の条件に当てはまるようになります。
if (screen === "create")
その結果、新規登録画面のJSXが表示されます。
同じように「編集」をクリックするとstate変数screenの値が
"edit"になり、編集画面が表示されます。
新規登録画面や編集画面の「一覧へ」では、
setScreen("list")を実行して一覧画面へ戻しています。
保存してブラウザを確認し、 「新規登録」「編集」で画面が変わり、「一覧へ」で戻ればOKです。
なぜsetScreenでStateを変更すると、
ブラウザの表示まで変わるのでしょうか。
更新関数setScreenでStateを更新すると、
Appコンポーネントが再レンダリングされます。
そのとき、Appの関数がもう一度実行され、
新しいStateの値を使って表示するJSXが決まります。
setScreen(...)
↓
Stateが更新される
↓
Appコンポーネントが再レンダリングされる
↓
Appの関数がもう一度実行される
↓
新しいscreenの値で表示するJSXが決まる
↓
必要な変更が画面へ反映される
このように、Stateが更新されるとReactはコンポーネントを再レンダリングし、 新しいStateの値に合わせて画面を更新します。
普通の変数の値を変更しても、それ自体をきっかけにReactが再レンダリングするわけではありません。 Stateを更新すると、Reactが新しいStateの値を使って表示を更新します。
今回登場したものを整理すると、次のようになります。
| 種類 | 今回登場したもの |
|---|---|
| React | State、useState、state変数、更新関数、Stateの更新による再レンダリング |
| JavaScript | ifによる条件分岐、分割代入 |
ReactではJavaScriptの機能を使いながら、 StateのようなReactの仕組みを組み合わせて画面を作っていきます。
useStateを使ってStateを用意できるscreenは現在の値を保持するstate変数setScreenはStateを更新する更新関数set + state変数名」とする名前が一般的
今回のApp.jsxの完成コードです。
state変数screenの値で一覧・新規登録・編集を切り替えます。
import { useState } from "react";
export default function App() {
const [screen, setScreen] = useState("list");
if (screen === "create") {
return (
<main className="form-screen">
<header className="screen-header">
<h1>気になるものリスト</h1>
<div className="header-actions">
<button type="button" className="secondary" onClick={() => setScreen("list")}>
一覧へ
</button>
</div>
</header>
<h2 className="screen-title">新規登録画面</h2>
</main>
);
}
if (screen === "edit") {
return (
<main className="form-screen">
<header className="screen-header">
<h1>気になるものリスト</h1>
<div className="header-actions">
<button type="button" className="secondary" onClick={() => setScreen("list")}>
一覧へ
</button>
</div>
</header>
<h2 className="screen-title edit-title">編集画面</h2>
</main>
);
}
return (
<main className="list-screen">
<header className="list-header">
<h1>気になるものリスト</h1>
<div className="header-actions">
<button type="button" onClick={() => setScreen("create")}>
新規登録
</button>
<button type="button" onClick={() => setScreen("edit")}>
編集
</button>
</div>
</header>
<h2 className="screen-title">一覧画面</h2>
</main>
);
}