はじめに
この記事は、普段ライブラリを使わない HTML + js (+ CSS) で Web 開発をしているエンジニアをターゲットに、なるべくおまじないで誤魔化さず納得してもらう、React入門記事です。
上述のターゲットにあたる友人に、Reactを教える際に作成した入門解説のマークダウンファイルを元に、少し改良した記事になります。本来公開する予定がなかったので需要は微妙ですが、もしあなたがターゲットにあたるエンジニアであれば、ぜひ活用してみてください。また、結構迂闊な物言いをした説明もちらほらありますが、初心者向けに大掴みな説明をしているということで見逃していただけますと… ![]()
また、迂闊な物言いをしているとは言ったものの、おまじないを避け納得してもらうため、初心者向けにしては踏み込んで解説している箇所もあります。React入門時には意味がわからない点も、慣れてきた後に読み返すとそういうことだったのかと思えるかもしれないので、何度か読み返しながら使ってもらえるとベターかと思っています。
React とは?
Meta(FaceBook) が開発した WebUI ライブラリです。
例えば appendChild のように、js では HTML の文書構造 (= DOM) を書き換えられる関数がいくつかあると思います。
イメージとしてはこういった関数を使い、HTML のタグを js 側で制御して組み上げて、HTMLファイルに流し込むようなライブラリです。
また、一般的に React での Web 制作を行う際は、js ファイルの中に HTML のタグのようなものが書ける記法、JSX 記法を用いることがほとんどです。
js ファイルの中で XML(HTML みたいなタグを使う記法全般の総称)を使うので JSX と呼びます。
以下は JSX ファイルのほんの短い一例です。ざっと見ると js ファイルのようですが、最後の行で、関数の引数に急にHTMLのような記法が混ざっています。これが JSX のプログラムの書き方です。
import { createRoot } from "react-dom/client";
const root = document.getElementById("root");
const reactRoot = createRoot(root);
reactRoot.render(<div>Hello World!</div>);
目次
ボリュームや学習ハードルとしては 1 ~ 4、5, 6、7, 8 の3つに分けてやっていくのが良さそうと思いながら書いています。目安に使ってください。
- npm を導入しよう
- ライブラリをインストールしよう
- vite の設定を書いておこう
- html ファイルを作ろう
- 試しに vite を動かしてみよう
- package.json の設定をしておこう
- jsx ファイルを作ろう
- JSX の記法と js の記法について知っておこう
- コンポーネントを作ろう
- useState を使おう
- useEffect を使おう
- 番外編: ビルドしてみよう
手順
0. 始める前に
この記事では実際に手を動かしながら React を書いてもらいます。PC で適当な場所にこのチュートリアル用のディレクトリを切り、そのフォルダを VSCode などで開くなどしてから読み進めてください。
コマンドをターミナルで実行する場合は、VSCode でターミナルを開き、そこで実行するのをおすすめします。
1. npm を導入しよう
js のパッケージマネージャー(ライブラリを管理するツール)は npm です。nodejs という js を CLI で実行するためのインタプリタをインストールすると npm がついてくるので、nodejs をインストールしましょう。すでに持っている方は次章に行って大丈夫です。
node -v や npm -v でインストールできたことを確認できたらOKです。次の章にいき、Reactに必要なライブラリをインストールしましょう。
2. ライブラリをインストールしよう
最低限必要なライブラリとして、react, react-dom, vite の3つが必要です。
react, react-dom はReact に関するライブラリです。js で作った DOM を HTML に流し込んだりする処理がこれに入ってるはずです。
vite は、JSX などの React のファイルを Web サイトとして見られるように、HTML と js に変換するツールです。直接 React とは関係ないですが、npm のライブラリを使って Web サイトを作る際にはこういう変換するビルドツールが必要です。
以下のコマンドで、その3つをインストールしましょう。
$ npm install react react-dom vite
これによって以下のファイル・フォルダが生成されたかと思います。
-
package.json- 必要なライブラリを記載したファイル
-
package-lock.json- ライブラリの細かいバージョン指定ファイル。手動で編集してはいけない
-
node_modules- ライブラリのファイルが詰まったフォルダ
また、package.json は以下のような中身になっているはずです。(細かいバージョンの数値は時期によって変わると思います)
{
"dependencies": {
"react": "^19.2.0",
"react-dom": "^19.2.0",
"vite": "^7.3.1"
}
}
vite の設定を書いておこう
今後 jsx ファイルを作成する際に、全てのファイルに以下のように import React from "react" という1行が必要になります。これが無いと React のコードとして動きません。(説明は省略しますが、React の都合で必要なコードではあります。)
import React from "react";
// 以下、React という値は使われない…
しかし、Reactという値を使わないのにimportするのは、手間はかかるしコードが汚れるしで、あまり嬉しくないですね。
ただし、vite の設定ファイルでは、この1行を書かずに済むような設定を記述できます。ので、その設定を書いていきましょう。
まず、設定ファイルの中で使う、@vitejs/plugin-react をインストールします。
$ npm install @vitejs/plugin-react
そして、vite.config.js というファイルを作成し、以下の内容を書き込んでください。
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
});
この設定は必須ではありませんが、書くことによって手間を省略することができるので、書いておくのをおすすめします。
3. html ファイルを作ろう
React は HTML の中の特定のタグに対して動的に子要素を生やしてページを書き換えるという仕組みで動いています。
一般的に <div id="root"></div> を配置した HTML を用意して、それを JS で制御します。
以下のようなindex.htmlのファイルを作りましょう。(<title>の中は各自好きに設定してください)
<!DOCTYPE html>
<html>
<head>
<title>REACT TUTORIAL</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
4. 試しに vite を動かしてみよう
npm で vite というライブラリを導入したと思います。
vite は、HTML と js ファイルを生成するライブラリであると同時に、開発時にリアルタイムで完成品の見た目を返す Web サーバーの役目もやってくれるのです。こいつ多機能なんです。
コマンドとして vite を呼び出すと、サーバーが立ち上がりますので、呼び出してみましょう。
コマンドとして npm のライブラリを呼び出す場合は、npx <ライブラリ名> と呼び出す必要があります。(ちなみに npm execute の略で npx) vite なら以下の通り。
$ npx vite
コマンドラインで以下のような出力が出たら OKです。出力で案内されているように、http://localhost:5173 にアクセスすれば、真っ白なサイトが出てくるはずです。(タブのタイトルは REACT TUTORIAL のように HTML ファイルの <title> が表示されていると思います。)
VITE v7.3.1 ready in 1575 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ press h + enter to show help
そして、vite のサーバーは、React の記述を書き進めるたびにファイルの変化を検知して、ページリロード無しで、リアルタイムで http://localhost:5173 の見た目が変わっていってくれます。(所謂ホットリロード)
package.json の設定をしておこう
余談ですが、npx を何度も叩くのは一般的でなく、何度も使うようなコマンドは package.json に書いておくのが一般的です。(今回はnpx viteと短いので恩恵は薄いが…)
package.json の scripts の部分にスクリプト名とその中身を書くと、npm run <スクリプト名>で呼び出せます。わからない方はとりあえず以下をコピペしておけば大丈夫です。
{
"scripts": {
"dev": "vite",
"build": "vite build"
},
"dependencies": {
"@vitejs/plugin-react": "^5.1.2",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"vite": "^7.3.1"
}
}
そして、以下のコマンドで vite が起動できたら OK です。
$ npm run dev
5. jsx ファイルを作ろう
JSX 記法を使うためには、拡張子は .js ではなく、.jsx とする必要があります。
名前はなんでもいいですが、ここでは src フォルダを作って src/main.jsx として進めます。
以下のようなファイルを作ってください。
import { createRoot } from "react-dom/client";
const root = document.getElementById("root");
const reactRoot = createRoot(root);
reactRoot.render(<div>Hello World!</div>);
そして、HTML ファイルでこのファイルを読み込む必要があります。
ここで、script タグに見慣れない属性があるなと思った人もいると思います。
main.jsx では、今回は react-dom というライブラリを import していますが、このように外部ライブラリを import したい場合は、type="module" という属性を script タグに付ける必要があります。
<!DOCTYPE html>
<html>
<head>
<title>REACT TUTORIAL</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="src/main.jsx"></script>
</body>
</html>
手順 4 で vite を起動しているはずなので、http://localhost:5173 にアクセスしてください。(起動していなければここで手順 4 の通りに vite を起動しましょう。)
Hello World! とページ左上に出てくれば OK です。
これで React の最低限の環境はできあがり!! ![]()
![]()
![]()
JSX の記法について知っておこう
この章の冒頭のコードでは、reactRoot.render 関数の引数として、div タグを渡しています。
js に慣れていると以下は変なコードに見えるかと思います。
reactRoot.render(<div>Hello World!</div>);
こういった、HTML のタグを js の値のように扱えるのが JSX の記法です。
変数に代入することも可能です。
divElement に代入された値などを JSX 式と呼びます。(数値、文字列、JSX式、辺りで横並びの概念と思っておいてください。)
const divElement = <div>Hello World!</div>;
reactRoot.render(divElement);
ここで、変数に入れるとき、複数行にまたがる場合は、() で囲う必要があります。
ある程度 React の記述が複雑になってくると、一行で記述する JSX 式はなかなか出なくなるので、基本的に () で囲う場面がほとんどになります。
const divElement = (
<div>
<p>Hello World!</p>
</div>
);
reactRoot.render(divElement);
また、タグの中に js の値を混ぜ込むこともできます。混ぜ込むときは {} で囲う必要があります。
const year = 2026;
reactRoot.render(<div>今年は {year} 年です。</div>);
// ページを開くと以下のように表示されるはず ↓
// 今年は 2026 年です。
さらに、数値以外にも JSX 式も混ぜ込むことができる値なので、JSX 式の中に JSX 式を入れるなんてこともできます。(以下4行目のコード)
const year = 2026;
const divElement = <div>今年は {year} 年です。</div>;
// JSX 式の中に JSX 式を入れることもできる(その場合も{}で囲う)
reactRoot.render(<div>{divElement}</div>);
そして、React で JSX 式を書く際に初心者が一番よく違反してしまう、とあるルールがあります。それは、「JSX 式は、一番親のタグは必ず1つになっていなければいけない」というものです。
説明だけでは理解が難しいかもしれないので、以下の例を確認してください。
const divElement = <div>Hello World!</div>;
const multiLineElement = (
<div>
<p>Hello World1!</p>
<p>Hello World2!</p>
</div>
);
// ↓これは駄目 (vite に怒られるはず)
const ngElement = (
<div>
<p>Hello World1!</p>
</div>
<div>
<p>Hello World2!</p>
</div>
);
ルールを守るためには、divタグなどで囲って違反を回避すればよいのですが、タグAの直下にタグBを置かなければいけないなど、そうはいかないケースもあるかと思います。
そんなときは、<></> という特殊なタグで囲うと、親タグが1つというルールを守りながら、複数のタグを扱えます。
const ngElement = (
<>
<div>
<p>Hello World1!</p>
</div>
<div>
<p>Hello World2!</p>
</div>
</>
);
reactRoot.render(ngElement);
// <></> で囲うと、最終的な HTML には <></> の部分が消されて出力される
// ngElement を渡すと ↓ な感じに出力される
/*
<div id="root">
<div>
<p>Hello World1!</p>
</div>
<div>
<p>Hello World2!</p>
</div>
</div>
*/
6. コンポーネントを作ろう
React の最大の魅力がコンポーネントです。例えばTwitterのツイートを表示する領域、Youtubeのサムネや投稿者情報を表示する領域など、見た目を使い回す時に非常に役立ちます。
例えばプログラムの手続きを関数としてまとめて、異なる部分を引数で受け取るように、JSX 式を1つのタグのように扱い、異なる部分を属性として受け取ることができます。
余談ですが、コンポーネントの作り方として、クラスコンポーネントと関数コンポーネントがあるのですが、もうクラスコンポーネントは使われず、関数コンポーネントが主流です。
以下の例を見てください。
const Information = () => {
const name = "鳩屋敷";
const age = 23;
const hometown = "福岡";
return (
<div>
<p>名前: {name}</p>
<p>年齢: {age}</p>
<p>出身: {hometown}</p>
</div>
);
}
// ↓ Information というコンポーネントを使いまわしてみてる
reactRoot.render(
<div>
<Information />
<Information />
<Information />
</div>,
);
JSX 式を return する関数を定義すると、コンポーネントとして利用できます。
一点注意すべきなのが、コンポーネント名は必ず大文字始まりで定義してください。小文字だと、そういう HTML のタグと勘違いされ、うまく動きません。
タグのように関数のコンポーネントを呼び出すと、return した JSX 式が呼び出されます。そのタグを並べるだけで、簡単に使い回すこともできます。もちろん、コンポーネントを編集するたびにコンポーネントを呼び出している箇所の見た目が一括で書き換わります。
さらに先程説明した通り、コンポーネントは引数を受け取れます。
関数コンポーネントは、HTML の属性のような記法で値を渡すと、json 形式の引数からその値を受け取れます。
HTML の属性の値の部分は文字列しか受け取らないので、数値などのような js の値を受け渡したい場合は {} で囲う必要があります。
例えば数値なら <Component number={12} /> みたいな感じですね。
// const Information = (props) => {
// const {name, age, hometown} = props;
// ↑ こんな感じの引数の展開を引数定義の段階でやっているイメージ
const Information = ({name, age, hometown}) => {
const introduction = () => {
alert(`${name}さんの年齢は${age}歳で、${hometown}出身の人だよ。`);
};
return (
<div>
<p>名前: {name}</p>
<p>年齢: {age}</p>
<p>出身: {hometown}</p>
<button onClick={introduction}>紹介するよ</button>
</div>
);
};
reactRoot.render(
<div>
<Information name="鳩屋敷" age={23} hometown="福岡" />
<Information name="タモリ" age={80} hometown="福岡" />
<Information name="さかなクン" age={50} hometown="東京" />
</div>,
);
ここで一点、React らしいコードの書き方の紹介です。
<button> タグの属性 onclick は文字列を受け取ったと思いますが、React ではそれは使わず、onClick (C が大文字)を使います。
<button onClick={onClickFunc}> といった感じで、onClick に js の値として関数オブジェクトを渡します。
onclick でも動くのは動くのですが、パフォーマンスが悪かったり、関数の参照性を広くしておく必要があるので、推奨はされません。
以上 onClick の紹介でした。
また、reactRoot.render関数にごちゃごちゃ書くのも一般的ではなく、Root や App など、React 全体のコンポーネントをまず切って渡すのが一般的です。reactRoot.render をするファイルとコンポーネントを定義するファイルも分けるのがベターです。
import { createRoot } from "react-dom/client";
import { App } from "./App.jsx";
const root = document.getElementById("root");
const reactRoot = createRoot(root);
reactRoot.render(<App />);
// ファイル分割する場合、外部から import できるように export と付ける必要がある
export const App = () => {
return (
// ここに Web サイトの見た目を書いていく
);
};
7. useState を使おう
ここからはコンポーネント内について考えていきます。js の reactRoot.render をしている部分や HTML ファイルについては考えないので頭の隅においておきましょう。
ボタンを押すと数字が増えるというページを作る、というケースを考えてみましょう。
以下のようなコードになるかと思います。
// ⚠ この例はうまく動きません
export const App = () => {
const count = 0;
const countUp = () => {
count += 1;
};
return (
<div>
<p>ボタンを押して数字を増やそう!</p>
<p>数字: {count}</p>
<button onClick={countUp}>押してね</button>
</div>
);
};
きっとボタンを押してもページは変わらなかったと思います。残念、React ではそんなページは作れないのか…そんなことはありません。
Reactのコンポーネントとは本来、引数を受け取って JSX 式を返すだけという、数学的な純粋な関数のようなものなのです。6 章で作った Information なんかが理想的なコンポーネントです(見栄えは、一切理想的ではないですが)。
引数によって見た目を変え、引数が同じであれば常に同じ見た目を描画するのが純粋なコンポーネントですが、実際はそうも言ってられません。事実、ボタンを押すと表示する数値が増える(=引数は変わらないのに見た目が変わる)ページを作りたいという需要がここにあります。
そんな、コンポーネントに 状態 (State) を持たせたいときに使えるのが、useState です。
中身を理解するよりかは、使い方を理解したほうがスムーズと思うので、内部処理は触れません。(というか私も useState の内部処理を把握せず使用しています)
実際に使うとこんな感じです。
const [value, setValue] = useState(0);
// ↓ こんな感じで、値と更新用関数が入っている(setValueの中身はあくまでイメージ)
// value = 0;
// setValue = (newValue) => { value = newValue; }
useState の引数には、状態として管理する値の初期値を入れる必要があります。
また、返り値は 2 つの値を持つ配列です。1 つ目はその描画したタイミングでの値、2 つ目は値を更新するための関数が入っています。
useState の返り値を受け取るときは、[xxx, setXxx] のように、配列を展開しつつ、<値の変数名> と set<値の変数名> で受け取るのが一般的です。
これを使って、ボタンを押すと数字が増えるというページを作るとこうなります。
// ↓ useState を import する必要がある
import { useState } from "react";
export const App = () => {
const [count, setCount] = useState(0);
const countUp = () => {
setCount(count + 1);
};
return (
<div>
<p>ボタンを押して数字を増やそう!</p>
<p>数字: {count}</p>
<button onClick={countUp}>押してね</button>
</div>
);
};
const count = 0; は useState の定義に変わり、0 は引数に移動しました。
また、count += 1 と加算していた処理は setCount(count + 1) と、更新用関数での更新に変わっています。
ボタンを押して、countUp が呼び出されて、setCount が呼び出されると、App の描画が再度実行されます。そして、再描画されたタイミングでは、setCount のおかげで、countの値が1増えた値に変わった状態で描画されます。
これで、ボタンを押すと数字が増えるというページが作れました。
setCount(0) とする関数を作れば、リセットボタンも作れると思います。数値を1減らす関数を作れば減らすボタンも作れますね。興味がある人はつくってみてください。
8. useEffect を使おう
コンポーネントの中の処理は全て描画されるたびに呼び出されます。
例えば useState の初期値を、WebAPI から取得した値にしたい場合を考えましょう。
- 関数コンポーネントの定義内で WebAPI を呼び出し、
-
setValueで更新し、 - 更新用関数が叩かれたのでもう一度コンポーネントの描画を始め、
- WebAPI を呼び出し、
-
setValueで更新し、 - 再描画して…
と無限ループしてしまいます。
以下のようなコードを書くと無限ループしてしまうのがわかるかと思います。
// ⚠ 無限ループしてしまい、PCに大きな負荷をかける可能性があります!
export const App = () => {
const [value, setValue] = useState(0);
// await を使うために関数に分けてます。
const initValue = async () => {
const result = await fetch("/api/hoge");
const responseBody = await result.json();
setValue(responseBody.value);
};
initValue();
// ↓ と同じことをしてる
// fetch("/api/hoge")
// .then((result) => {
// result.json().then((body) => {
// setValue(body.value);
// });
// });
return <div>{value}</div>;
};
こんなコードを書きたくなる場面があるのは至極当然と思います。しかし、先程も言った通り、Reactのコンポーネントは、引数を受け取って JSX 式を返す純粋な関数のような役割が望ましいのです。
が、こちらも当然そういったコードが書けないというわけではありません。useEffect を使用すると、そういったレンダリングと直接関係のない 副作用 (Side Effect) の処理も行う事ができます。
副作用という言葉は主に関数型プログラミングの文脈での用語で、一般的な単語としての副作用とは若干ニュアンスが違います。副作用の一般的なイメージを想像すると、API 呼び出しを副作用と呼ぶのは違和感があるかと思いますが、「コンポーネントを呼び出し、HTML が描画される」ことが主作用だと考えると、それ以外の計算処理などを副作用と呼ぶのも納得できるかと思います。
useEffect も、使い方を見ていきましょう。
実際に使うとこんな感じです。
useEffect(
// 第一引数:副作用として実行する関数
() => {
fetch("/api/hoge");
},
// 第二引数:副作用を実行するタイミングを決める依存配列(あとで説明)
[]
);
第一引数は実行する関数、第ニ引数は依存配列を指定します。
第一引数はいいとして、第ニ引数の依存配列ってなんだって人が全員かと思います。文章だけだと理解が厳しいかと思うので、実際のコードと併せて解説します。
以下のコードを見てみてください。Component というコンポーネントが定義されており、Component を呼び出すなにかしらの外側のコードがあるとイメージしてください。一応 Component を呼び出す App も書いてみましたが、今見てほしいのは Component です。
const Component = ({userName, num}) => {
useEffect(() => {
console.log(userName);
document.title = `こんにちは、${userName}さん`;
}, [userName]);
return <div>{userName} {num}</div>;
};
const App = () => {
const [userName, setUserName] = useState("");
const [num, setNum] = useState(0);
const onChangeName = (event) => {
setUserName(event.target.value);
};
const onChangeNumber = (event) => {
setNum(Number(event.target.value));
};
return (
<div>
<div>
名前:
<input value={userName} onChange={onChangeName} />
</div>
<div>
数字:
<input value={num} type="number" onChange={onChangeNumber} />
</div>
<Component userName={userName} num={num} />
</div>
);
};
コンポーネントは引数が変われば新しく描画処理が走ります。
この場合、引数の userName という値が呼び出し側の処理で変化すると、そのたびに useEffect が実行され、console.log は呼び出され、ページの title も書き換わります。
しかし、num の値が呼び出し側の処理で変わった際には、div の中の num の部分だけ値が変わり、useEffect の処理は呼び出されないのです。
useEffect の副作用の処理は、依存配列の中の変数の値が変わったかどうかで処理を呼び出すかスキップするかを判定します。今回の依存配列の中の変数は userName のみであり、描画時に userName の値が前回の描画から変わった時にのみ、副作用の処理は実行されるのです。
実際に、この例の useEffect の副作用の処理の中身は num には依存しておらず、逆に userName の値には依存しています。そのため、依存配列は [userName] と書く必要があるのです。
章頭で紹介した、useState の初期値を API から取得した値にしたい場合のコードを useEffect を使って修正すると以下のような感じになります。
const App = () => {
const [value, setValue] = useState(0);
useEffect(() => {
const initValue = async () => {
const result = await fetch("/api/hoge");
const responseBody = await result.json();
setValue(responseBody.value);
};
initValue();
}, []);
return <div>{value}</div>;
};
厳密ではないですが、大まかな処理の順としては、
- App の描画が始まる
- value が 0 で初期化される
- 初回の描画なので
useEffectが副作用を実行 - API を呼び出し、
setValueを実行 - div を描画
-
setValueを呼び出したのでもう一度 App の描画が始まる - value が API の値で更新されている
- 2回目以降の描画なので
useEffectの依存配列をチェック - 配列の中の変数の値が変わっていない(そもそも変数が入っていない)ので、副作用の実行をスキップ
- div を描画
と言う感じです。
useEffect の副作用をいつ実行するかがこの依存配列で決まり、useEffect は、コンポーネントの初回の描画時と配列の中の値が変わったときに実行されます。
この場合、副作用として更新する値を配列に入れない(配列を空にしてもよい)でおけば、副作用の処理を何度も実行せずに済みます。
9. 番外編: ビルドしてみよう
vite の設定で、npm run build を導入しているかと思います。手順 4 の後半、package.json の設定をしておこう の章で scripts を追加したときに、build というスクリプトもこっそり追加してました。
実行してみましょう。
$ npm run build
実行すると、dist というディレクトリが作られているかと思います。
そのフォルダがこの React で作ったサイトの完成品になります。これをそのまま HTML サーバの配信対象フォルダとして配置すると、React で作成したページを見ることができるはずです。