更新ログ
この記事は数年前に書いたものですが有り難いことに新年度が近づくと読んでくださる方がいらっしゃるようで、古い内容では不都合が生じることもあるかと思い不定期にはなりますが最新情報に更新したいと思います。
読んでくださった皆様にこの場を借りてお礼申し上げます。
- 2025/1 : 現時点最新のReactに対応、全体の文章校正・最新化
はじめに
本記事はReactにこれから一歩を踏み出したいけどチュートリアルの難しい言葉理解してる時間はあまりない、という方に向けて、環境の構築からなんとなく画面が動くまでを解説します。
今回はReact + TypeScriptをベースに説明します。
これを読んでもっと知りたいと思った方は是非公式チュートリアルをお試しください。
https://ja.react.dev/learn
目次
環境構築
Node
まずはパッケージ管理ツールであるnpmを利用するためにNodeをインストールします。
インストール
下のリンクからnodeのインストーラをダウンロードし、インストールを行ってください。
https://nodejs.org/ja/
CLIがわかる方はそちらでインストールしていただいても問題ありません。
Nodeとnpmのインストール確認
うまくいけばnodeとnpmのバージョンが表示されます。
(バージョンの数字が一致しなくても問題ありません、ある程度新しいものを利用しましょう)
node -v
v23.3.0
npm -v
10.9.0
Visual Studio Code
インストール
次に、統合開発環境のVisual Studio Code
をインストールします。
Atomなどでも問題ないですが、個人的に一番便利なのがVisual Studio Code
だと思っています。
https://code.visualstudio.com/download
日本語化
必要に応じて日本語化が可能です。
- Visual Studio Codeを開き、サイドバーから拡張機能のストアに移動します。
- 検索欄に
Japanese
と打ち、Japanese Language Pack
をインストールします。 - Visual Studio Codeを再起動します。
うまくいかない場合、F1
を押して画面上部に出る「コマンドパレット」にdisplay
と入力し、Configue Display Language
を選択、「日本語(ja)」を選択すると変更できます。
Reactの導入
インストール
今回はcreate react app
という、react公式が提供している環境の一括インストールを利用します。
数年前まではCreate React App
が主流でありこの記事でも紹介しておりましたが、2023年にサポートが終わっており利用をお勧めしません。
代わりにViteというものを利用してインストールを行います。
Visual Studio Codeを開き、フォルダを開くで開発に使いたいフォルダを開きます。
その状態で画面上部のタブから「ターミナル」を開き、「新しいターミナル」をクリックします。
画面下部にターミナルというツールが表示されるので、下記のコマンドを入力してください。
npx create vite@latest
Need to install the following packages:
create-vite@6.1.1
Ok to proceed? (y)
create-viteをインストールしますか?と聞かれるのでYesと答えます。
> npx
> create-vite
? Project name: ›
ここで作成するフォルダの名前を決めます(英語が良いです)
✔ Project name: … test
? Select a framework: › - Use arrow-keys. Return to submit.
Vanilla
Vue
❯ React
Preact
Lit
Svelte
Solid
Qwik
Angular
Others
どれで開発するか聞かれるため、今回はReact
を選択します。
他のフレームワークを勉強するときもViteが楽に準備してくれるので、とても助かります。
✔ Select a framework: › React
? Select a variant: › - Use arrow-keys. Return to submit.
TypeScript
❯ TypeScript + SWC
JavaScript
JavaScript + SWC
React Router v7 ↗
開発に使う言語等を聞かれます。今回はTypeScript + SWC
を選択します。
SWC
はあまり気にしなくてもよいですが御幣を恐れずに言うと「一部プロセスが高速に動く」という感じです。
✔ Select a variant: › TypeScript + SWC
Scaffolding project in /home/terao/work/test...
Done. Now run:
cd test
npm install
npm run dev
これで完了です!
画面左側に新しいフォルダが作られていると思います。
画面上部の「ファイル」タブをクリックして「フォルダーを開く」から新しく作られた開発用フォルダを開いてください。
確認
このようにいくつかのファイルが生成されていればインストール成功です。(おそらくコードの内容などは若干違いますが問題ありません)
では、実際に動かしてみましょう。
npm install
ターミナルに上記のコマンドを入力してください。
いろいろな文字が流れ、また入力できるようになったら完了です。
これはコードを動かすのに必要な様々なものをインストールしています。
「ライブラリ」等で調べると色々出てくるのでいずれ勉強していただければと思います。
次に下記のコマンドをターミナルに入力してください。
npm run dev
ターミナルにこんな文字が表示されれば成功です。
Local: http://localhost:5173
ターミナルの3行目に記載されたこのURLをブラウザで開いてみてください。
このような画面が表示されたと思います。
これで無事Reactの導入完了になります。
Reactの書き方
動かしてみる
まずは試しに今開いているサンプルページを少し触ってみましょう。
{プロジェクト名}/src/App.tsx
を開き、19行目の文字をHello World!
にしてみましょう。
保存するとターミナルに文字が走り、自動的にページが更新されるはずです。
このように、Reactではホットリロードという自動更新機能がデフォルトで導入されています。
.tsxファイル
次に.tsx
というファイルについて簡単に説明します。
先程App.tsx
という名前のファイルを編集しました。見慣れない拡張子だと思いますが、これは「React特有の書き方を利用したファイル」という意味になります。(JavaScriptの場合.jsx
となります)
特徴としては、関数の返り値にHTMLを記載するところが他の記法との大きな違いになります。
Reactの考えとしては「ロジック(JavaScript)とマークアップ(HTML)を別々に書く」従来の技術の分離ではなく、「ロジック(JavaScript)とマークアップ(HTML)を機能ごとにひとまとめにする」という関心の分離を採用しているため、このような記法になります。
コンポーネントとは
Reactについて調べていると、しばしば「コンポーネント」という単語を目にします。
コンポーネントとはロジックとマークアップを両方含む疎結合の部品を指します。
つまり、同じ機能を必要な場所で何度も再利用できるように機能ごとに分離して管理するという考え方です。
ページの余白等を決めるコンポーネント
↓
ページに含まれるコンテンツのコンポーネント
↓
コンテンツに含まれるアイテムコンポーネント
実際に書いてみる
実際に動くコードを作ってみます。
まずは先程見たApp.tsx
の中身をシンプルなものにしてみましょう。
function App() {
return (
<div className="App">
<h1>Hello World!</h1>
</div>
);
}
export default App;
画面を見るとただ「Hello World!」と白い画面に表示されています。
先程話題に出たように、関数の返り値がHTMLになっていることが分かりやすく見えると思います。
変数の利用
このように書き換えてみましょう
function App() {
const text: string = 'Hello World!';
return (
<div className="App">
<h1>{text}</h1>
</div>
);
}
export default App;
画面を見ると何も変化がないことがわかると思います。
上記のように、変数をHTML内に入れられるのも.tsx
の特徴です。
ルーティング
次はボタンを押したら画面が遷移されるようにしたいと思います。
まずは下記の画面遷移に使うライブラリをインストールします。
npm i react-router-dom
まずApp.tsxを下記のように変更します。
import { Link } from "react-router-dom";
export const App = () => {
const title: string = "Hello World!";
return (
<div className="App">
<h1>{title}</h1>
<Link to='/test'>
ボタン
</Link>
</div>
);
}
{プロジェクト名}/src/test.tsx
を作成し下記のコードを記述します。
export const Test = () => {
const title: string = "test";
return (
<div className="Test">
<h1>{title}</h1>
</div>
);
}
その後、{プロジェクト名}/src/main.tsx
を下記のように編集します。
ここでルーティングするURLやコンポーネントを指定しています。
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import "./index.css";
import { App } from "./App";
import { Test } from "./test";
import { BrowserRouter, Route, Routes } from "react-router-dom";
createRoot(document.getElementById('root')!).render(
<StrictMode>
<BrowserRouter>
<Routes>
<Route path="/" element={<App />} />
<Route path="/test" element={<Test />} />
</Routes>
</BrowserRouter>
</StrictMode>,
)
画面に戻り、ボタンを押すと画面が切り替わる(遷移する)ことが分かると思います。
子コンポーネントとprops
今度はコンポーネント内でコンポーネントを呼び出してみましょう。
コンポーネントの説明で説明したように、コンポーネントは機能を分割したものになります。そのため、例えば画面コンポーネントの中にボタンコンポーネントを呼び出したいという場合は、コンポーネントをコンポーネントの中に呼ぶ、親子関係のような構造が出来上がります。
{プロジェクト名}/src/components/link.tsx
を作成し下記のコードを記述します。
type LinkButtonProps = {
text: string,
link: string
}
export const LinkButton = (props: LinkButtonProps) => {
return (
<div className="LinkButton">
<Link to={props.link}>
{props.text}
</Link>
</div>
);
}
この時、link.tsx
にtype
というものを宣言しています。
これは型宣言と呼ばれるもので、この型を利用した場合はオブジェクト型でstring型のtext
とstring型のlink
しかこの変数に入りませんという意味になります。TypeScriptはこうやって型を指定していくことで変な値の出入りを防いでいます。
次にApp.tsxを下記のように変更します。
import { LinkButton } from "./children/LinkButton";
export const App = () => {
const title: string = "Hello World!";
return (
<div className="App">
<h1>{title}</h1>
<LinkButton text="ボタン" link="/test" />
</div>
);
}
画面を見るとルーティングの時と同じように動作しているのが分かります。
link.tsx
は3行目の関数の引数に先程作成した型を指定しています。
このコンポーネント関数の引数がprops
と呼ばれるもので、親コンポーネントから子コンポーネントへ値を受け渡すことが可能になります。
親側で書いた処理を子に渡すことで、子が不要な処理を抱え込まずに済むのがメリットです。
つまり、担当する機能を分割したままにコンポーネントを細かく増やすことができるのです。
React Hooksとstate
まずはこのように「増やす」ボタンを押したらnum
が加算されるように書いてみます。
import { LinkButton } from "./children/LinkButton";
export const App = () => {
const title: string = "Hello World!";
let num: number = 0;
const increment = () => {
num += 1;
console.log(num);
};
return (
<div className="App">
<h1>{title}</h1>
{num}回押しました。
<LinkButton text="ボタン" link="/test" />
<button type="button" onClick={increment}>増やす</button>
</div>
);
}
この書き方では画面の文字が変わらない事が分かります。
Reactでは、値の更新はとある方法で検知させないと画面に反映がされません。
ここで登場するのが状態管理、stateになります。
簡単に説明すると関数の状態を必要な時だけ更新することで、常に最新のHTMLを最低限の処理で返却するという機能です。
いくつか方法がありますが、今回はReact Hooksと呼ばれる機能を利用します。
下記のようにコードを修正してください。
import { useState } from "react";
import { LinkButton } from "./children/LinkButton";
export const App = () => {
const title: string = "Hello World!";
const [num, setNum] = useState(0);
const increment = () => {
setNum(num + 1);
console.log(num);
};
return (
<div className="App">
<h1>{title}</h1>
{num}回押しました。
<LinkButton text="ボタン" link="/test" />
<button type="button" onClick={increment}>
増やす
</button>
</div>
);
}
画面を見ると表示される数字が更新されていることが分かります。
このように、必要な時だけ画面レンダリングを行うことが可能になります。
また、画面右側のconsoleの数字が画面に対して1低いことが気になった方もいるかと思います。
これはstateの更新は一瞬で済むものではなく、多少時間がかかってしまうため即時に変更後の値を取り出すのは難しいことを表しています。
この値が更新されたことを検知する方法もあるのですが、さらに多くのHooksを理解する必要があるため今回は省略します。
state管理に関するHooksについて紹介した記事があるのでそちらも参照していただけると理解が深まるかと思います。
https://qiita.com/r-terao/items/10d6fe6047f1d117b59a
(これもいつか更新します)
おわりに
今回はReact + TypeScriptの環境構築から、ある程度コーディングすることが可能なレベルまでのチュートリアルをなるべく単語数少なめで紹介させていただきました。
Reactの良いところは、やはり関心事の分離という考え方にあると思います。
これを利用することで、例えば複数画面で再利用されるボタンコンポーネントを先に作ってから大人数で同時に利用して作業しても、処理部分を持っているのは呼び出す側のコンポーネントのためコンフリクトを起こしにくいのです。
このように大量にコンポーネントを生み出すような規模の大きい開発で大いに役立つReactというフレームワークを皆様一度利用してはいかがでしょうか?