「Reactの学習で必ず登場するuseStateが何をしているのかわからない」
「Reactでpropsの渡し方がうまくできないことがある」
「なんでコンポーネント化をしないといけないのか謎なまま学習している」
ReactなどのモダンJSは通常のJavaScriptやjQueryに比べると学習ハードルが急に上がります。
その原因の一つとして専門用語が多く、モダンJS特有の価値観を理解しないといけないということがあると思います。
今回は最低限知っておきたい「props」「useState」の2点について、効果と役割を解説してみたいと思います。
動画もあるので一緒にご覧いただくとより理解が深まると思いますので確認してみてください。
Reactのpropsは何のためにあるか?
まずpropsについてです。
propsとは?みたいな切り口で説明しても頭に入りづらいと思いますので、「propsを使わない書き方」を一緒に見てみましょう。
ユーザーの一覧を画面に表示するような機能を想定して以下のようなコーディングをしました。
import React from "react";
const PropsBasic = () => {
return (
<div>
<div>
<h3>田中太郎</h3>
<p>
<span>19</span>歳
</p>
<p>男</p>
</div>
<hr />
<div>
<h3>鈴木大介</h3>
<p>
<span>19</span>歳
</p>
<p>男</p>
</div>
<hr />
<div>
<h3>山田花子</h3>
<p>
<span>18</span>歳
</p>
<p>女</p>
</div>
</div>
);
};
export default PropsBasic;
「名前」「年齢」「性別」という3項目が記載されたユーザーを3件表示したことになります。
HTMLを書いているだけなので特に難しいことはないのですが、同じ項目で同じレイアウトを繰り返し書いているので冗長に感じられます。
そこでpropsを使った書き方に変えてみましょう。
propsを使うためにはどこかの部分を別のファイルに切り出すことになります。
今回はユーザー1件分の表示をStudent.jsという別のJSファイルに切り出してみます。
1件目の田中太郎のものをそのままコピペすればOKです。
import React from "react";
const Student = () => {
return (
<div>
<h3>田中太郎</h3>
<p>
<span>19</span>歳
</p>
<p>男</p>
</div>
);
};
export default Student;
上記のように特定の部分を別のファイルに切り出すことをコンポーネント化と言い、切り出されたファイル単体をコンポーネントもしくはコンポーネントファイルと呼びます。
機械やプラモデルを分解して部品だけを取り出すようなイメージです。
コンポーネントに切り出したものは元あったファイルでは以下のようにインポートして使用します。
import React from "react";
// ここを追加。コンポーネントをインポートする。
import Student from "./component/Student";
const PropsBasic = () => {
return (
<div>
{/* ここを変更 */}
<Student />
</div>
);
};
export default PropsBasic;
冒頭でやったような3件分のユーザーを表示したい場合は以下のようにコンポーネントを3回書くことになります。
HTMLとテキストをそのまま3回分書くよりスッキリしたコードになりますね。
import React from "react";
import Student from "./component/Student";
const PropsBasic = () => {
return (
<div>
{/* ここを変更 */}
<Student />
<hr />
<Student />
<hr />
<Student />
</div>
);
};
export default PropsBasic;
同じような表示になっていますがテキストが全て同じものになっていますね。
理由は単純で田中太郎の分をそのままコピペでコンポーネント(Student.js)に書いているからです。
import React from "react";
const Student = () => {
return (
<div>
<h3>田中太郎</h3>
<p>
<span>19</span>歳
</p>
<p>男</p>
</div>
);
};
export default Student;
propsはこのような「同じコンポーネントを中身の値を変えて使い回したいとき」に使います。
それではコンポーネント(Student.js)とコンポーネントをインポートするファイル(PropsBasic.js)の中をpropsで書き換えます。
import React from "react";
import Student from "./component/Student";
const PropsBasic = () => {
return (
<div>
{/* ここを変更 */}
<Student name="田中太郎" age="19" gender="男" />
<hr />
{/* ここを変更 */}
<Student name="鈴木大介" age="19" gender="男" />
<hr />
{/* ここを変更 */}
<Student name="山田花子" age="18" gender="女" />
</div>
);
};
export default PropsBasic;
import React from "react";
{/* ここを変更 */}
const Student = ({ name, age, gender }) => {
return (
<div>
{/* ここを変更 */}
<h3>{name}</h3>
<p>
{/* ここを変更 */}
<span>{age}</span>歳
</p>
{/* ここを変更 */}
<p>{gender}</p>
</div>
);
};
export default Student;
冒頭でやったような表示と同じにすることができました。
コンポーネントであるユーザー情報のなかで動的に変更したい部分を「名前」「年齢」「性別」の3点です。
それら3点を好きな名前にして値を格納したものをpropsと言います。
一緒ではないですが変数が一番近いイメージかもしれません。
import React from "react";
import Student from "./component/Student";
const PropsBasic = () => {
return (
<div>
{/* name,age,genderの3点をpropsにして値をそれぞれ格納する */}
<Student name="田中太郎" age="19" gender="男" />
<hr />
<Student name="鈴木大介" age="19" gender="男" />
<hr />
<Student name="山田花子" age="18" gender="女" />
</div>
);
};
export default PropsBasic;
用意したpropsはコンポーネント(Student.js)では関数の引数の中で「{ }」を使って記載します。
そうすることで用意したname, age, genderという3点のpropsをコンポーネント(Student.js)の中で使うことができます。
こちらも変数に近いイメージで、「田中太郎」など直接テキストを書いていた部分をpropsの名前で置き換えます。
import React from "react";
{/* ここに{}でprops名を記載 */}
const Student = ({ name, age, gender }) => {
return (
<div>
{/* nameというpropsに置き換える */}
<h3>{name}</h3>
<p>
{/* ageというpropsに置き換える */}
<span>{age}</span>歳
</p>
{/* genderというpropsに置き換える */}
<p>{gender}</p>
</div>
);
};
export default Student;
propsを使うことで同じレイアウトを切り出して中身の値のみ動的に変更することができます。
さらにpropsを使ったコンポーネントファイルでコーディングすることで全体のコードが見やすくなりますね。
ReactのuseStateは何をしているのか?
続いてuseStateについてです。
こちらもuseStateの言葉の意味を解説しても分かりづらいと思いますので、「useStateを使わない書き方」を見ていきます。
今回の内容はカウンターを想定します。
import React from "react";
const UseStateBasic = () => {
let count = 0;
const handleCurrentCount = (num) => {
if (num === -1) {
count = count - 1;
}
if (num === +1) {
count = count + 1;
}
};
return (
<div>
<div>
<button onClick={() => handleCurrentCount(-1)}>-</button>
<button onClick={() => handleCurrentCount(+1)}>+</button>
<p>{count}</p>
</div>
</div>
);
};
export default UseStateBasic;
プラスとマイナスのボタンと現在の数字を表示するだけの簡単なコーディングで作ってみました。
現在の数字は変数countとして初期値は0にしています。
また数字をカウントする関数をhandleCurrentCountという名前で作り、引数によって数字をカウントするようにしました。
関数handleCurrentCountは引数に+1を受けると現在の数字に1を加算して、引数に-1を受けると現在の数字から1を減算します。
+1か-1かの引数はプラスボタンかマイナスボタンのどちらがクリックされたかで変わるような仕組みです。
import React from "react";
const UseStateBasic = () => {
// 数字をcountという変数にする
let count = 0;
const handleCurrentCount = (num) => {
// 引数に-1を受けたら減算
if (num === -1) {
count = count - 1;
}
// 引数に+1を受けたら加算
if (num === +1) {
count = count + 1;
}
};
return (
<div>
<div>
{/* 関数handleCurrentCountの引数に-1を渡す */}
<button onClick={() => handleCurrentCount(-1)}>-</button>
{/* 関数handleCurrentCountの引数に+1を渡す */}
<button onClick={() => handleCurrentCount(+1)}>+</button>
<p>{count}</p>
</div>
</div>
);
};
export default UseStateBasic;
上記のコードは実際には動作しませんが、JavaScriptの基本的な文法で書いた場合を比較のために紹介しました。
続いて上記の内容をuseStateを使ったコードで書き換えてみます。
useStateを使うには1行目でインポートしておく必要があります。
// useStateをインポートしておく
import React, { useState } from "react";
const UseStateBasic = () => {
const [count, setCount] = useState(0);
const handleCurrentCount = (num) => {
setCount((currentCount) => {
return currentCount + num;
});
};
return (
<div>
<div>
<button onClick={() => handleCurrentCount(-1)}>-</button>
<button onClick={() => handleCurrentCount(+1)}>+</button>
<p>{count}</p>
</div>
</div>
);
};
export default UseStateBasic;
まず変数countの書き方が変わっています。
useStateは関数になっていて引数に変数countの初期値を書くのがルールです。
今回だと0になるのでuseState(0)となります。
また先ほどのコードには無かったsetCountというものがあります。
こちらは変数countの中身を変えるための関数で、カウント自体はsetCountによって実行されることになります。
そのため関数handleCurrentCountの中身にsetCountを記載しています。
setCountの中身はカウント処理を書くことになるので、引数(-1か+1)を受け取って現在の数字(変数count)と合算するようなものを書きました。
// useStateをインポートしておく
import React, { useState } from "react";
const UseStateBasic = () => {
// 現在の数字を変数countに、countを更新するsetCount関数、countの初期値をuseStateの引数に指定
const [count, setCount] = useState(0);
const handleCurrentCount = (num) => {
// 現在の数字currentCountに引数の-1か+1を合算することで変数countが変わる
setCount((currentCount) => {
return currentCount + num;
});
};
return (
<div>
<div>
<button onClick={() => handleCurrentCount(-1)}>-</button>
<button onClick={() => handleCurrentCount(+1)}>+</button>
<p>{count}</p>
</div>
</div>
);
};
export default UseStateBasic;
setCountやuseStateなど、いきなり専門用語が登場すると難しく見えがちですが、結局は書き方が変わっただけで通常のJavaScriptに過ぎないわけですね。
今回はReactを例題にしていますがVueなど他のモダンJSにも横展開できる内容ですのでぜひ練習しておきましょう。