├── README.md
├── phase1
├── handouts
│ ├── 1-HTMLとは.md
│ ├── 2-演習.md
│ └── README.md
└── samples
│ └── answer-2_3.html
├── phase2
└── handouts
│ ├── 1-はじめに.md
│ ├── 2-数値演算.md
│ ├── 3-文字列.md
│ ├── 4-変数.md
│ ├── 5-配列.md
│ ├── 6-オブジェクト.md
│ ├── 7-制御構文.md
│ ├── 8-関数.md
│ └── README.md
└── phase3
├── handouts
├── 1-はじめに.md
├── 2-基本.md
├── 3-コンポーネント.md
├── 4-検索機能の発展.md
├── 5-ルーティング.md
├── 6-まとめ.md
└── figures
│ ├── fig0.png
│ └── fig1.png
└── samples
├── data
├── articles
│ ├── test1.md
│ ├── test2.md
│ └── test3.md
└── index.json
└── repo
├── .gitignore
├── README.md
├── jsconfig.json
├── next.config.mjs
├── package.json
├── src
├── app
│ ├── articles
│ │ └── [id]
│ │ │ └── page.js
│ ├── layout.js
│ ├── page-client.js
│ └── page.js
└── components
│ ├── ArticleContent.js
│ ├── Form.js
│ ├── FormClient.js
│ └── ListItem.js
└── yarn.lock
/README.md:
--------------------------------------------------------------------------------
1 |
2 | IPC Web 研修 2024
3 | 2024/1/31 – 2/1
4 | ⭐️
5 | by いなにわうどん / ちゅるり
6 |
7 |
8 |
9 | このリポジトリは 2024/1/31 – 2/1 に開催される IPC Web 研修 2024 の研修資料リポジトリです。主に IPC の開発未経験の 1 年生を対象としています。本研修では 2 日間で HTML, JavaScript の入門から Next.js によるモダンな Web 開発までを体験することを目標としています。
10 |
11 | ## 内容
12 | 1 日目にフェーズ 2 まで、2 日目には 3 以降に進むことを想定しています。
13 | - phase1
14 | - フェーズ 1 では HTML に入門し、HTML を用いた簡単な Web ページの作成を体験します。
15 | - phase2
16 | - フェーズ 2 では JavaScript を勉強し、HTML に組み込んで使用する方法について学習します。
17 | - phase3
18 | - フェーズ 3 ではこれまでに学習したことを応用し、Next.js によるモダンな Web 開発を実践します。
19 | - phase4
20 | - フェーズ 4 では「動くもの」から「使えるもの」へを目標とし、CSS の入門や Cloudflare を用いたバックエンドの作成など、より実践的な開発手法を学びます。
21 |
22 | ## 構成
23 | - phase*
24 | - handouts:講義資料。Markdown 文書で構成されます。
25 | - samples:サンプルのソースファイル等。フェーズ毎に異なります。
26 |
--------------------------------------------------------------------------------
/phase1/handouts/1-HTMLとは.md:
--------------------------------------------------------------------------------
1 | # 1 - HTML とは
2 | ## 1.1 概要
3 | HTML とは Hyper Text Markup Language の略で、Web ページの構造を記述するために用いるマークアップ言語です。記述とはタイトルや画像、テキストやリンクなどのことを指します。通常、Web ページを構築する際には HTML でドキュメントを構築し、CSS を用いてページにデザインを与えます。必要に応じて JavaScript 等の言語を使用してページにインタラクティブな要素を追加したり、追加の通信を行うこともあります。ここで注意したいのは、**HTML は Web ページのデザインを記述するものではない**という点です。あくまでも **Web ページに載せるドキュメントを記載するものであるため、常に最小限でシンプルであること**が求められます。
4 |
5 | ## 1.2 HTML の構造
6 | ### 1.2.1 タグ
7 | 次の Listing1 は、最小限の HTML ドキュメントです。
8 |
9 | ---
10 | **Listing1:最小限の HTML**
11 | ```html
12 |
13 |
14 | Hello, World
15 |
16 |
17 | ```
18 | ---
19 |
20 | ---
21 | **演習1**
22 |
23 | `practice-1.html` を作成し、Listing1 のコードを記述・保存して Web ブラウザで表示させてみましょう(ヒント:VSCode のファイルツリー上の HTML ファイルを Web ブラウザ上にドラッグ & ドロップすることで表示させることができます)。
24 |
25 | ---
26 |
27 | HTML では **タグ**と呼ばれる要素を階層的に記述することによってドキュメントを構築します。タグは `` や `` のことを指し、とりわけ `` を**開始タグ**、`` を**終了タグ**と呼びます。また `xxx` の部分を**タグ名**と呼び、開始タグと終了タグで囲まれた部分を**要素**と言います。なお、**HTML ではタグ名として使用できる文字列は決まっています**が、React をはじめとしたコンポーネント指向の Web 開発フレームワークを使用する場合にはその限りではありません(厳密にはそれらのフレームワークで使用する言語は HTML ではなく、JSX や TSX などと呼ばれる、拡張された HTML と JavaScript をあわせたような言語を使用します)。
28 |
29 | 先程、HTML を階層的に記述することによってドキュメントを構築すると述べました。これは、要素の中に要素を入れ込むことができることに所以します(これを**ネスト**と言います)。タグの種類にもよりますが、基本的には**要素の中には 0 個以上の任意の要素を入れることができます**。Listing1 の例では、body 要素の中に html 要素が、html 要素の中に p 要素が存在しています。
30 |
31 | ### 1.2.2 属性
32 | 次の Listing2 は Listing1 の HTML を少しだけ改変したものです。
33 |
34 | ---
35 | **Listing2:最小限の HTML(改変)**
36 | ```html
37 |
38 |
39 | Hello, World
40 |
41 |
42 | ```
43 | ---
44 |
45 | ---
46 | **演習2**
47 |
48 | `practice-2.html` を作成し、Listing1 のコードを記述・保存して Web ブラウザで表示させてみましょう。おそらく `Hello, World` の文字が赤色になったことでしょう。
49 |
50 | ---
51 |
52 | `p` 要素の中に `style="color: red"` という記述が追加されました。これが**属性**です。属性は開始タグの中に `a="b"` の形で記述し、複数個記述する場合には属性どうしを空白スペースで区切ります。特に属性に関して `a` の部分を**属性名**、`b` の部分を**属性値**と呼びます。Listing2 の例では `a` が `style` に、`b` が `"color: red"` に該当します(これらの属性の意味は割愛します)。各タグでは使用できる要素が予め定められており、これは MDN などのドキュメントで確認することができます。
53 |
54 | ### 1.2.3 HTML の構造
55 | HTML ドキュメントは、ほとんどの場合次のような構造をしています。
56 |
57 | ---
58 | **Listing3:HTMLの構造**
59 | ```html
60 |
61 |
62 |
63 |
64 |
65 |
66 | Hello, World
67 |
68 |
69 | ```
70 | ---
71 |
72 | この HTML をファイルに記述して表示させても Listing1 の実行結果と遜色ないことでしょう。これは、Listing3 は Listing1 の内容にメタデータを加えただけのものであるためです。一般に、HTML にはテキストをはじめとした文書情報だけではなく、文書に関連するメタデータも同時に記述します。そのため、最終的な HTML ファイルは次のような構造となります。
73 |
74 | - `DOCTYPE` 宣言
75 | - この HTML 文書のバージョン情報を記述します。現行の最新バージョンである HTML Living Standard ではファイル先頭にこのように記述することが求められます。この記述を省略した場合、一部のブラウザでは HTML 互換モードと呼ばれるモードで HTML ファイルが読み込まれ、JavaScript の多くの機能が動作しなかったり、一部の HTML 要素が正しくレンダリングされなくなったりする可能性があります。
76 | - `html` 要素
77 | - すべての HTML 要素はこの中に記述される必要があります。
78 | - `head` 要素
79 | - この要素の中では、文書中には記述しない(する必要のない)文書のメタデータを記述します。この要素内で行う代表的なメタデータの扱いに、文字コードの指定や外部 CSS / JS の読み込みがあります。
80 | - Listing3 の例にある `meta` 要素は文字コードの宣言を行っています。終了タグがないため誤っているように見えますが、これは正しい記述です。このような要素を **空要素**と呼びます。
81 | - `body` 要素
82 | - この要素の中で実際に文書の内容を構成します。
83 |
84 | ## 1.3 HTML でよく使用される要素
85 | この項では HTML でよく使用されるタグについて説明します。各項目には MDN における詳細説明のリンクを置いているので、適宜参考にしてください。
86 |
87 | 実際にはここに記述していない数多くの要素があります。MDN の [HTML 要素リファレンス](https://developer.mozilla.org/ja/docs/Web/HTML/Element)にすべての要素の説明があるので、必要に応じて参照してください。また吉川ウェブによる [HTML5 入れ子チートシート](https://yoshikawaweb.com/element/)では、どの要素をどの要素にいれて良いかを確認することができるので、実際の開発中には大いに役立つと思われます。
88 |
89 | ### article:記事
90 | [記事コンテンツ要素](https://developer.mozilla.org/ja/docs/Web/HTML/Element/article)
91 |
92 | > 文書、ページ、アプリケーション、サイトなどの中で自己完結しており、(集合したものの中で)個別に配信や再利用を行うことを意図した構成物を表します。例えば、フォーラムの投稿、雑誌や新聞の記事、ブログの記事、商品カード、ユーザーが投稿したコメント、対話型のウィジェットやガジェット、その他の独立したコンテンツの項目が含まれます。
93 |
94 | ### section:セクション
95 | [汎用セクション要素](https://developer.mozilla.org/ja/docs/Web/HTML/Element/section)
96 |
97 | > 文書の自立した一般的なセクション(区間)を表します。そのセクションを表現するより意味的に具体的な要素がない場合に使用します。少数の例外を除いて、セクションには見出しを置いてください。
98 |
99 | **セクションには見出しを置くこと**が重要です。
100 |
101 | ### h1-h6:見出し
102 | [HTML の見出し要素](https://developer.mozilla.org/ja/docs/Web/HTML/Element/Heading_Elements)
103 |
104 | > セクションの見出しを 6 段階で表します。`` が最上位で、`` が最下位です。
105 |
106 | ### p:段落
107 | [段落要素](https://developer.mozilla.org/ja/docs/Web/HTML/Element/p)
108 |
109 | > テキストの段落を表します。視覚メディアにおいて、段落はふつう隣接するブロックと上下の空白や最初の行の字下げによって隔てられたテキストのブロックとして表現されますが、 HTML の段落は画像やフォーム欄などの関連するコンテンツを構造的にまとめることができます。
110 |
111 | ### ul / li:順序なしリスト
112 | [順序なしリスト要素](https://developer.mozilla.org/ja/docs/Web/HTML/Element/ul)
113 |
114 | > 項目の順序なしリストを表します。一般的に、行頭記号を伴うリストとして描画されます。
115 |
116 | ### ol / li:順序付きリスト
117 | [順序付きリスト要素](https://developer.mozilla.org/ja/docs/Web/HTML/Element/ol)
118 |
119 | > 項目の順序付きリストを表します。ふつうは番号付きのリストとして表示されます。
120 |
121 | ### a:アンカー
122 | [アンカー要素](https://developer.mozilla.org/ja/docs/Web/HTML/Element/a)
123 |
124 | > href 属性を用いて、ウェブページ、ファイル、メールアドレス、同一ページ内の場所、または他の URL へのハイパーリンクを作成します。
125 |
126 | ### img:画像埋め込み
127 | [画像埋め込み要素](https://developer.mozilla.org/ja/docs/Web/HTML/Element/img)
128 |
129 | > 文書に画像を埋め込みます。
130 |
131 | ### div:コンテンツ区分
132 | [コンテンツ区分要素](https://developer.mozilla.org/ja/docs/Web/HTML/Element/div)
133 |
134 | > フローコンテンツの汎用コンテナーです。 CSS を用いて何らかのスタイル付け(例えば、スタイルが直接適用されたり、親要素にフレックスボックスなどの何らかのレイアウトモデルが適用されるなど)がされない限り、コンテンツやレイアウトには影響を与えません。
135 |
136 | ## 1.4 さいごに
137 | 冒頭では HTML について次のように述べました。
138 |
139 | > **HTML は Web ページのデザインを記述するものではない**という点です。あくまでも **Web ページに載せるドキュメントを記述するものであるため、常に最小限でシンプルであること**が求められます。
140 |
141 | 一般に、文書は構造化されていればされているほどよいとされています。適切に構造化された文書はアクセシビリティ、検索性に優れ、人間にも計算機にもわかりやすいコンテンツとなります。究極には、Web ブラウザによってレンダリングされていない生の HTML コードを読むだけで、内容のどの部分とどの部分が関連付けられているかやどこまでが一つの区切りかが分かるような状態が望ましいです。優れた HTML は、コード上のコメントを読まずとも(あるいは存在しなくとも)他の人が実装者の意図やページの構造が分かるなど、チーム開発においても効果を発揮します。
142 |
143 | また、世の中にはデザインを無効化する「リーダーモード」を使用して Web を閲覧する人がいます。リーダーモードとは CSS を外した状態の HTML のみをレンダリングする Web ブラウザの機能です。加えて視覚障がいを持つ方々の中には、スクリーンリーダと呼ばれる Web ページを読み上げる機能を使用する人がいます。こういった機能は Web ページが適切に構造化されていることを前提にして成立していますが、もしあなたの作成した HTML ドキュメントがデザインや面倒臭さのために突飛な構造になっていたらどうでしょうか。趣味の範囲内のページであれば問題がないかもしれませんが、多くの人がアクセスするページであれば、それだけで批判の対象になったり、ページランクの低下、ユーザ数の低下などに繋がります。そういった問題を避けるためにも、適切に構造化された HTML を書くことは常に意識したいものです。
--------------------------------------------------------------------------------
/phase1/handouts/2-演習.md:
--------------------------------------------------------------------------------
1 | # 2 - 演習
2 | ## 2.1 要素の使い分け
3 | 次の画像 Image1 は [Yahoo! JAPAN](https://www.yahoo.co.jp/) の PC 版におけるトップページのスクリーンショットです。この中で `article` 要素、`section` 要素、`footer` 要素に該当する部分はそれぞれどの部分でしょうか。ソースコードを見ずに考えてみましょう。
4 |
5 | また、なぜその要素で実装されているかについても考えてみてください。
6 |
7 | ---
8 | Image1:Yahoo! JAPAN のトップページ(2024/1/31 )時点
9 |
10 | 
11 |
12 | ---
13 |
14 | 終わったら開発者ツールで確認してみましょう。開発者ツールは Google Chrome の場合、F12(ノート PC の場合 fn + F12 の場合もあります)を押して起動することができます。起動後、下の Image2 のように、開発者ツール左上のボタンを押してページ上の任意の要素をクリックすることにより、その要素を構成する HTML を確認することができます。
15 |
16 | ---
17 | Image2: 開発者ツール
18 |
19 | 
20 |
21 | ---
22 |
23 | ## 2.2 アクセシビリティを考慮した HTML
24 | [Yahoo! JAPAN](https://www.yahoo.co.jp/) の トップページでは、「HTML 上には存在するが実際には表示されていない見出し」が数多くあります。先程述べた開発者ツールを使用して、このような例を探してみましょう。また、なぜこのような実装になっているかを考えてみましょう。
25 |
26 | ## 2.3 HTML を使用したページの作成
27 | 下のようなページを出力する HTML 文書を `practice-2_3.html` として作成してください。見た目があっていれば大丈夫ですが、できるだけ**文書の構造化**を意識することを心がけてください。なお解答例は `samples/answer-2_3.html` にあります。
28 |
29 | 
--------------------------------------------------------------------------------
/phase1/handouts/README.md:
--------------------------------------------------------------------------------
1 | # フェーズ1:HTML
2 | このフェーズでは、HTML 言語の性質を学んだのち、実際に HTML を用いて簡単な Web ページを作成する方法を学びます。
3 |
4 | ## 事前準備
5 | このフェーズでは、常に手を動かしながら学ぶことが求められるため、作業をするためのディレクトリが必要です。このフェーズの学習を始める前に、自分の作業ディレクトリに `phase1` ディレクトリを作成してください。以降、このフェーズにおける演習は `phase1` ディレクトリ内で作業するものとします。また特に断りのない限り、エディタには **VSCode** を使用するものとします。
--------------------------------------------------------------------------------
/phase1/samples/answer-2_3.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | ブログ記事一覧
9 |
10 |
11 |
12 | 2023/12/25:クリスマス
13 | 今日はクリスマスらしいので、お肉を食べました。
14 |
15 |
16 |
17 |
18 |
19 | 2023/12/24:ゲーム
20 | 友人とゲーム大会をしました。3 つほどゲームをしました。
21 |
22 | - Minecraft
23 | - ポケモン
24 | - Wii Sports
25 |
26 | Wii Sports ではボウリングをやり、順位をきめました!
27 |
28 | - 私
29 | - 太郎さん
30 | - 花子さん
31 |
32 | 優勝できてよかったです!
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/phase2/handouts/1-はじめに.md:
--------------------------------------------------------------------------------
1 | # 1 - はじめに
2 | **JavaScript**はクライアント側(ユーザの Web ブラウザ)で実行されるオブジェクト指向型のプログラミング言語です。よく Java と混同されますが、全くの別物です。JavaScript を用いることで Web ページに動きを加えたり、フォームに入力された内容を検証・送信したりすることができます。
3 |
4 | ## 1.1 試してみよう
5 | 任意の Web ページを開き、右クリック → 検証 から開発者ツールを開いてください。そしてコンソールタブに移り、Image1 が示すような場所に `1 + 1` と入力して Enter キーを押してみましょう。`2` と表示されるはずです。
6 |
7 | ---
8 | Image1:開発者ツールでの実行
9 |
10 | 
11 |
12 | ---
13 |
14 | このように JavaScript は本来 HTML に埋め込んで使用する言語ですが、小さいプログラムであれば開発者ツールから直接実行することができます。
15 |
16 | 従来、JavaScript は Web ブラウザ上で実行するプログラミング言語でしたが、近年では Node.js や Bun、Deno といったツールの登場によりネイティブで直接実行することができるようになりました。本研修で扱う Next.js も Node.js 上に構築されたソフトウェアであり、サーバーサイドで JavaScript が実行されています。
17 |
18 | また JavaScript は**動的型付け言語**と呼ばれ、実行時にプログラム中のデータ型が決定されます。これに対し、Java などの言語は**静的型付け言語**と呼ばれ、コーディング時に厳格にデータ型を指定し、コンパイル時や実行時に型の検証を行います。動的型付け言語はスクリプト言語(JavaScript や Python など)によく見られます。このような言語は取り掛かりやすく、コード量が少なく、記述時に型を深く考えないで良いなどの利点がありますが、その反面でエラーが起こりやすいなどの問題があります。特に大規模な開発になるとバグを産みやすく、設計の根幹を揺るがす事態になることもしばしばです。
19 |
20 | 近年は端末の高性能化などにより、Web サイトや Web アプリケーションの規模はますます大きく、複雑になってきています。JavaScript においては特にこの傾向が顕著で、前述の問題が指摘されるようになりました。そこで登場したのが **TypeScript** です。TypeScript は Microsoft 社によって開発されている静的型付け言語です。この言語の最大の特徴として、**JavaScript のスーパーセットである**という点が挙げられます。すなわち **JavaScript の構文は TypeScript においても正しい構文である**ことです。JavaScript の構文を阻害しないように型の定義ができるようになったのが TypeScript であるため、JavaScript からの移行がしやすく、学習コストが低いことも併せて爆発的に普及しました。今日では Web 開発のスタンダードとなっています。
21 |
22 | 本研修でも TypeScript を扱いたかったのですが、2 日間という制約上、型の概念の説明などで時間がかかってしまうことが予想されたため JavaScript を使用することにしました。ですが、JavaScript が書けるようになったらぜひ TypeScript にも挑戦してほしいと思います。
23 |
24 | ## 1.2 HTML での使用
25 | 次のコード Listing1 は HTML と JavaScript を併用する場合の例です。
26 |
27 | ---
28 | Listing1:HTML と JavaScript の併用
29 |
30 | ```html
31 |
32 |
33 |
34 |
38 |
39 |
40 | ```
41 |
42 | ---
43 |
44 | ---
45 | **演習1**
46 |
47 |
48 | `practice-1.html` を作成し、その中に Listing1 のコードを記述してブラウザで表示させてみましょう。こんにちは!と表示されるはずです。
49 |
50 | ---
51 |
52 | HTML において JavaScript を使用する際には **`script` タグを使用します**。`script` タグの中に記述された JavaScript のコードは、基本的にはこれを含む HTML ファイルが Webブラウザによって読み込まれた瞬間に実行されます。今後、この資料ではこのタグの中に JavaScript のコードを記述していくこととします。
53 |
54 | `console.log()` 関数を使用すると、引数に渡された任意の値を開発者ツールのコンソールに表示することができます。
55 |
56 | ---
57 | **演習2**
58 |
59 |
60 | `practice-2.html` を作成し、その中に Listing1 の `alert` の部分を `console.log` に置き換えたコードを記述してブラウザで表示させてみましょう。開発者ツールのコンソールタブにこんにちは!と表示されるはずです。
61 |
62 | ---
63 |
64 | **`console.log()` は今後極めて多く使用するので、必ず覚えておいてください。**
65 |
66 | 余談:Listing1 のコードでは `alert` 関数を使用しています。この関数の挙動をよく観察してみると、表示されたポップアップの「OK」を押すまではいかなる操作も受け付けてくれません。この挙動を面白がったある女子中学生は、とある掲示板では JavaScript のコードを投稿するとそのまま実行されるバグがあることを見つけて、無限ループの中で `alert` 関数を呼び出すようなコードを書いて投稿しました。数日後、彼女は不正指令電磁的記録供用未遂の疑いで家宅捜索・補導されてしまいました。なんともしょうもないというか、悲しい事件ですね(参考:[アラートループ事件](https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%A9%E3%83%BC%E3%83%88%E3%83%AB%E3%83%BC%E3%83%97%E4%BA%8B%E4%BB%B6))。
--------------------------------------------------------------------------------
/phase2/handouts/2-数値演算.md:
--------------------------------------------------------------------------------
1 | # 2 - 数値演算
2 | 本章では数値演算について述べます。特に断りのない限り、`1 - はじめに` の章で作成した `practice-2.md` の `script` タグ内でコードを実行してみてください。
3 |
4 | ## 2.1 式と数値リテラル
5 | `1 + 1.1` のように、数学で用いられる数式のような記述を**式**と呼びます。この記述は JavaScript の世界でも妥当です。一方で `1` や `1.1` のように、これ以上分割することのできない数値を**数値リテラル**、あるいは単に**数値**と呼びます。なお**数値リテラルは式でもあります**。
6 |
7 | 数値リテラルには次のようなものがあります:
8 |
9 | - 10進数
10 | - 整数:`1`、`10`、`123`...
11 | - 小数:`1.234`...
12 | - 2進数:`0b00`、`0b01`
13 | - 16進数:`0x01`、`0xfe`...
14 |
15 | 式は式または数値リテラルどうしを**演算子**によって結合したものとして表されます。演算子とは `+` や `-` といった記号です。数値計算をするための演算子を**算術演算子**と呼びますが、基本的な算術演算子には次のようなものがあります:
16 |
17 | - `+`:足し算
18 | - `-`:引き算
19 | - `*`:掛け算
20 | - `/`:割り算
21 | - `%`:剰余算(あまり)
22 | - `**`:べき乗
23 |
24 | 算術演算子のみによる式を**算術式**と呼び、この式はまた数値を表します。
25 |
26 | ---
27 | **演習1**
28 |
29 | 次のコードを実行し、結果が `3` であることを確認しましょう。また、思いつくいくつかの式を実行して、演算子間に優先順位があることを確かめてください。実際の数学と一致するでしょうか。
30 |
31 | ```javascript
32 | console.log(2 * 2 - 1);
33 | ```
34 |
35 | ---
36 |
37 | ## 2.2 真偽値
38 | 真か偽を表す概念として、**真偽値**があります。JavaScript では `true` または `false` によって表されます。式の演算結果として真偽値を返すような式を**関係式**と呼びます。関係式を表現するには次に挙げるような**関係演算子**を使用します。
39 |
40 | - `<`:小なり
41 | - `>`:大なり
42 | - `<=`:小なりイコール
43 | - `>=`:大なりイコール
44 | - `==`:等値演算子
45 | - `!=`:非等値演算子
46 | - `===`:同値演算子
47 | - `!==`:非同値演算子
48 |
49 | ---
50 | **演習2**
51 |
52 | 次のコードを実行し、結果が `true` であることを確認しましょう。
53 |
54 | ```javascript
55 | console.log(2 < 3);
56 | ```
57 |
58 | 次の場合、結果は同じになるでしょうか(ヒント:文字列は `'` または `"` で囲って表現します)。
59 |
60 | ```javascript
61 | console.log(123 == '123');
62 | console.log(123 === '123');
63 | ```
64 |
65 | 結果が同じにならない場合、その理由を調べてみましょう(MDN:[等価](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Equality) / [同値](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Strict_equality))。
66 |
67 | ---
68 |
69 |
--------------------------------------------------------------------------------
/phase2/handouts/3-文字列.md:
--------------------------------------------------------------------------------
1 | # 3 - 文字列
2 | ## 3.1 文字列リテラルの記述
3 | JavaScript において文字列を表現するには、対象の文字列を `'` または `"` で囲って表現します。例えば `"このようになります"`。これを**文字列リテラル**と呼びます。 `'` と `"` の使い分けは特にありませんが、チーム開発などの現場においてはどちらかで統一される場合がほとんどです。
4 |
5 | ---
6 | **演習1**
7 |
8 | 次のコードを実行し、`こんにちは` と表示されることを確認しましょう。また、`'` を取り除くとどうなるかも確認しておきましょう。
9 |
10 | ```javascript
11 | console.log('こんにちは');
12 | ```
13 |
14 | ---
15 |
16 | ## 3.2 改行とエスケープシーケンス
17 | 文字列の中で改行を表現するには、`\n` を使用します。例えば `'行1\n行2'` のようになります。この場合 `\n` や `n` は表示されず、純粋に改行を示します。このように、`\ + 一文字` で特殊な文字を表現する記法を**エスケープシーケンス**と呼びます。他にもタブ文字を表す `\t` などがあります。
18 |
19 | また、文字列中で `'` や `"` を使用する際にも役立ちます。例えば `'` で囲われた文字列の中で `'` を使用したい場合には、`'僕は\'太郎\'です'` のように表現します。
20 |
21 | ---
22 | **演習2**
23 |
24 | 次のコードを実行し、2 行に渡って `行1` `行2` と表示されることを確認しましょう。
25 |
26 | ```javascript
27 | console.log('行1\n行2');
28 | ```
29 |
30 | エスケープシーケンスによる `'` の使用も試してみましょう。
31 |
32 | ```javascript
33 | console.log('僕は\'太郎\'です');
34 | ```
35 |
36 | ---
--------------------------------------------------------------------------------
/phase2/handouts/4-変数.md:
--------------------------------------------------------------------------------
1 | # 4 - 変数
2 | ## 4.1 導入
3 | 例えば 200 円のノートと 100 円のノートをいくつか買って比較する場合のプログラムについて考えてみます。愚直に書くと次の Listing1 のようなコードになるでしょう。
4 |
5 | ---
6 | Listing1:おつかい
7 |
8 | ```javascript
9 | console.log(200 * 6 + 100 * 2);
10 | console.log(200 * 5 + 100 * 3);
11 | console.log(200 * 4 + 100 * 5);
12 | ```
13 |
14 | ---
15 |
16 | これでも良いのですが、ノートやペンの価格が変わった場合にはどうでしょう。3 つの式のそれぞれの値段を書き換える必要があってかなり面倒です。ここが変数の使いどきです。Listing2 のように変数に予め値段を代入しておくことで、何度も書き換えずに済むようになります。
17 |
18 | ---
19 | Listing2:おつ改
20 |
21 | ```javascript
22 | let note = 200;
23 | let pen = 100;
24 |
25 | console.log(note * 6 + pen * 2);
26 | console.log(note * 5 + pen * 3);
27 | console.log(note * 4 + pen * 5);
28 | ```
29 |
30 | ---
31 |
32 | また、変数にはもう一つの重要な役割があります。それは**右辺の式や値に名前をつけること**です。例えば `200 * 4 + 100 * 5` のような式をなんの前提知識も持たずに見たときに、何を示しているか分かるでしょうか。前後の文脈からある程度推測することができる場合もありますが、これが難しい場合も多くあります。これが `let sum = 200 * 4 + 100 * 5` となっていれば、この式が合計を示していることが明らかになり、コードが格段に読みやすくなります。
33 |
34 | ---
35 | **演習1**
36 |
37 | 次のコードに 800 円の `book` 変数を追加し、ノート 4 個、ペン 3 本、本 4 冊の合計金額を算出してみましょう。
38 |
39 | ```javascript
40 | let note = 200;
41 | let pen = 100;
42 |
43 | console.log(note * 4 + pen * 3); // ?
44 | ```
45 |
46 | ---
47 |
48 | ## 4.2 変数の宣言
49 | 前項では雰囲気で使ってしまいましたが、JavaScript において変数を宣言する場合には `let`、`const`、`var` のいずれかのキーワードを使用して次のように記述します。
50 |
51 | ---
52 | Listing3:変数の宣言
53 |
54 | ```javascript
55 | // 宣言時に値を代入する
56 | let note = 200;
57 | const pen = 100;
58 | var book = 800;
59 | ```
60 |
61 | ```javascript
62 | // 先に宣言だけをしてあとから代入する
63 | let note;
64 | var book;
65 |
66 | note = 200;
67 | book = 800;
68 | ```
69 |
70 | ---
71 |
72 | `let`、`const`、`var` にはそれぞれ使い分けがあります。
73 |
74 | - `let`
75 | - `let` 宣言された変数は、その後のプログラムで**再度代入することができます**。しかし、同じ名前で再度変数を宣言することはできません。一方で**変数のスコープ**(変数を使用できる範囲)は、この変数が宣言された**ブロック**(`{` と `}` で囲まれた範囲のこと)、その子のブロックのみです。
76 | - `const`
77 | - **再代入できない**点を除いて `let` と同様です。
78 | - 一見すると不便そうに見えますが、基本的に**プログラムはその後にできる操作をできるだけ制限する方向で記述すつほうがよい**とされているので、再代入させたくない変数があるならば積極的に使用すべきです。
79 | - `var`
80 | - `let` 宣言された変数は、その後のプログラムで**再度代入することができ**、また再度同じ名前で変数を宣言することができます。スコープも緩く、この変数が宣言された関数内であればどこでも使用することができます。一見便利そうに見えますが、**スコープの範囲がゆるいがゆえバグの温床になりやすく、現在ではあまり使用されません**。
81 |
82 | これに関しては [JavaDrive のサイト](https://www.javadrive.jp/javascript/var/index2.html#section3)にわかりやすい記述があるので、適宜参照してください。
83 |
84 | ## 4.3 undefined
85 | 次の Listing4 のように、変数の宣言だけして値を代入しない場合、その変数は `undefined` で初期化されます。別の値を代入すると `undefined` ではなくなりますが、明示的に `undefined` を代入したい場合には Listing5 のように `undefined` キーワードを使用します。
86 |
87 | ---
88 | Listing4:undefined
89 |
90 | ```javascript
91 | let note;
92 | console.log(note); // undefined
93 | ```
94 |
95 | ---
96 |
97 | ---
98 | Listing5:undefined の使用
99 |
100 | ```javascript
101 | let note = 200;
102 | console.log(note); // 200
103 |
104 | note = undefined;
105 | console.log(note); // undefined
106 | ```
107 |
108 | ---
109 |
110 | ## 4.4 変数の命名
111 | 基本的にアルファベット(大文字・小文字)と数字、_を使用することができますが、数字を先頭にすることはできません。また、多くの場合命名には**キャメルケース**が使用されます。ただし、変数名には[ここ](https://www.javadrive.jp/javascript/ini/index5.html#section1)で示されているような**予約語**を使用することはできません。
112 |
113 | ### 4.3.1 キャメルケース
114 | ある名前が一つの単語で構成されるならばその単語の小文字表記を、複数の単語の連結で表現したいのであれば最初の単語は小文字表記で、以降の単語は大文字始まりで連結していくというものです。JavaScript をはじめとして、Java や TypeScript、Kotlin などで使用されます。
115 |
116 | 例:`result`、`bookPrice`、`bookCasePrice`...
117 |
118 | ### 4.3.2 アッパーキャメルケース
119 | キャメルケースに似ていますが、全ての単語を大文字で始めるという点で異なります。C# で主に使用されます。
120 |
121 | 例:`Result`、`BookPrice`、`BookCasePrice`...
122 |
123 | ### 4.3.3 スネークケース
124 | 全ての単語を小文字で構成し、単語の区切りに `_` を使用する手法です。Python や Rust などでよく使われています。
125 |
126 | 例:`result`、`book_price`、`book_case_price`...
127 |
128 | ### 4.3.4 ケバブケース
129 | スネークケースの `_` を `-` に置き換えたものです。CSS などで使用されます。
130 |
131 | 例:`result`、`book-price`、`book-case-price`...
132 |
133 | ---
134 | **演習2**
135 |
136 | 自分の知っている言語で推奨されている命名規則を調べてみましょう。
137 |
138 | ---
--------------------------------------------------------------------------------
/phase2/handouts/5-配列.md:
--------------------------------------------------------------------------------
1 | # 5 - 配列
2 | ## 5.1 概要
3 | JavaScript で配列を扱うには `[]` を使用します。次の Listing1 はいくつかの配列の宣言方法を示しています。配列の n 番目の要素にアクセスするには `[n]` を使用します。n を**インデックス**と呼び、その範囲は **0 から 要素数 - 1** です。
4 |
5 | ---
6 | Listing1:配列
7 |
8 | ```javascript
9 | const numbers = [0, 1, 2, 3, 4, 5];
10 | console.log(numbers); // [0, 1, 2, 3, 4, 5]
11 |
12 | const alphabets = ['a', 'b', 'c'];
13 | console.log(alphabets); // ['a', 'b', 'c']
14 | console.log(alphabets[0]); // a
15 | console.log(alphabets[1]); // b
16 | console.log(alphabets[2]); // c
17 |
18 | alphabets[1] = 'x'; // 代入
19 | console.log(alphabets[1]); // x
20 | ```
21 |
22 | ---
23 |
24 | 配列の長さを取得するには `length` プロパティにアクセスします。
25 |
26 | ---
27 | Listing2:配列の長さ
28 |
29 | ```javascript
30 | const numbers = [0, 1, 2, 3, 4, 5];
31 | console.log(numbers.length); // 6
32 | ```
33 |
34 | ---
35 |
36 | 配列の中に配列を入れることもできます。
37 |
38 | ---
39 | Listing2:二次元配列
40 |
41 | ```javascript
42 | const numbers = [[1, 2], [3, 4], [5, 6]];
43 | console.log(numbers[0]); // [1, 2]
44 | ```
45 |
46 | ---
--------------------------------------------------------------------------------
/phase2/handouts/6-オブジェクト.md:
--------------------------------------------------------------------------------
1 | # 6 - オブジェクト
2 | JavaScript における**オブジェクト**は、**関連するデータや機能を1つのまとまりにして扱うための仕組み**です。オブジェクトは、キーと値の組み合わせを使って情報を格納します。これにより、データの整理と管理が容易になります。
3 |
4 | オブジェクトを作成するには、オブジェクトは波括弧 `{}` でくくり、中にキーと値を指定します。キーと値はコロン `:` で区切り、各ペアはコンマ `,` で区切ります。例を見てみましょう。
5 |
6 | ---
7 | Listing1:オブジェクトの作成
8 |
9 | ```javascript
10 | // 空のオブジェクトを作成
11 | let myObject = {};
12 |
13 | // キーと値を持つオブジェクト
14 | let person = {
15 | name: "John",
16 | age: 25,
17 | isStudent: true
18 | };
19 | ```
20 |
21 | ---
22 |
23 | オブジェクトの値にアクセスするには、**ドット演算子(`.`)** か角括弧 `[]` を使います。
24 |
25 | ---
26 | Listing2:オブジェクトの値にアクセスする
27 |
28 | ```javascript
29 | // ドット演算子
30 | console.log(person.name); // John
31 | console.log(person.age); // 25
32 |
33 | // 角括弧記法
34 | console.log(person['name']); // John
35 | console.log(person['age']); // 25
36 | ```
37 |
38 | ---
39 |
40 | 既存のオブジェクトに新しいキーと値を追加したり、既存の値を更新したりできます。
41 |
42 | ---
43 | Listing3:オブジェクトの値を更新する
44 |
45 | ```javascript
46 | // 新しいキーと値を追加
47 | person.gender = "Male";
48 |
49 | // 既存の値を更新
50 | person.age = 26;
51 | ```
52 |
53 | ---
--------------------------------------------------------------------------------
/phase2/handouts/7-制御構文.md:
--------------------------------------------------------------------------------
1 | # 7 - 制御構文
2 | ## 7.1 条件分岐
3 | JavaScript において条件分岐を行う場合には、**if 文**を使用します。if 文は次の Listing1 のように記述します。
4 |
5 | ---
6 | Listing1:if 文
7 |
8 | ```javascript
9 | // if 文
10 | if (条件式) {
11 | // 処理
12 | } else {
13 | // 条件式に該当しなかった場合の処理
14 | }
15 |
16 | // if-elseif 文
17 | if (条件式1) {
18 | // 条件式1に該当した場合の処理
19 | } else if (条件式2) {
20 | // 条件式2に該当した場合の処理
21 | } else {
22 | // 条件式に該当しなかった場合の処理
23 | }
24 | ```
25 |
26 | ---
27 |
28 | 各 if 文において `else` 節や `else if` 節は省略することもできます。条件式の部分には算術式や関係式が入りますが、JavaScript では真偽値以外の値も入れることができます。これは truthy / falthy の考え方で、truthy なオブジェクトは真と、falthy なオブジェクトは偽と判定されます。
29 |
30 | - truthy なオブジェクト
31 | - `true`
32 | - `0` 以外の数値
33 | - `null` や `undefined` でないオブジェクト
34 | - falthy なオブジェクト
35 | - `false`
36 | - `0`
37 | - `null`
38 | - `undefined`
39 |
40 | ## 7.2 繰り返し文:`for`
41 | JavaScript において繰り返しを実現する構文には `for` と `while` がありますが、まずは `for` について説明します。`for` は指定された回数、または配列に関して繰り返す場合に使用します。次の Listing2 では 0 から 99 までの数値を順に表示します。
42 |
43 | ---
44 | Listing2:for 文
45 |
46 | ```javascript
47 | for (let i = 0; i < 100; i++) {
48 | console.log(i);
49 | }
50 | ```
51 |
52 | ---
53 |
54 | for 文の `()`の中では次の 3 つの記述をし、それぞれを `;` で区切ります。なおこれら全てが省略可能で、例えば `for (;;)` のように記述すると無限ループとなります。
55 |
56 | - 1 番目:for 文内で使用する変数の宣言
57 | - 2 番目:繰り返し条件式(ここが `true` の間ループが繰り返される)
58 | - 3 番目:一度繰り返すごとにする処理
59 |
60 | また、配列のすべての要素を走査するには次のようにします。
61 |
62 | ---
63 | Listing3:配列における for 文
64 |
65 | ```javascript
66 | const alphabets = ['a', 'b', 'c'];
67 | for (let i = 0; i < alphabets.length; i++) {
68 | console.log(alphabets[i]);
69 | }
70 | ```
71 |
72 | ---
73 |
74 | ---
75 | **演習1**
76 |
77 | 足し算などの算術演算をせずに(3 番目のインクリメントを除く)1 から 200 までを表示してみましょう。
78 |
79 | ---
80 |
81 | ## 7.3 繰り返し文:`while`
82 | `while` 文も JavaScript における繰り返し処理です。for 文とは異なり、繰り返し条件式のみを記述するシンプルな繰り返しです。次の Listing3 は `while` 文の構文です。`while` 文では条件式が `true` の間処理を繰り返します。
83 |
84 | ---
85 | Listing4:while 文
86 |
87 | ```javascript
88 | while (条件式) {
89 | // 処理
90 | }
91 | ```
92 |
93 | ---
94 |
95 | ---
96 | **演習2**
97 |
98 | `while` 文を使って 1 から 100 までの数字を表示してみましょう。
99 |
100 | ---
101 |
102 | ## 7.4 `continue` と `break`
103 | 繰り返し(`for` や `while`)の処理の途中で繰り返しの最初に戻りたい場合や繰り返しをやめたい場合には、`continue` や `break` を使用します。前者の場合には `continue` を、後者の場合には `break` を記述します。次の Listing4 は、for 文において 50 を表示した瞬間に繰り返しを抜ける例です。
104 |
105 | ---
106 | Listing5:break
107 |
108 | ```javascript
109 | for (let i = 0; i < 100; i++) {
110 | console.log(i);
111 |
112 | if (i === 50) {
113 | break;
114 | }
115 | }
116 | ```
117 |
118 | ---
--------------------------------------------------------------------------------
/phase2/handouts/8-関数.md:
--------------------------------------------------------------------------------
1 | # 8 - 関数
2 | ## 8.1 概要
3 | **関数**は、実行する特定のタスクや処理をまとめたもので、名前をつけて呼び出すことができます。関数は、コードの再利用や構造化に役立ちます。基本的な構文は次の通りです。
4 |
5 | ---
6 | Listing1:関数の構文
7 |
8 | ```javascript
9 | function 関数名(パラメータ1, パラメータ2, ...) {
10 | // 関数の本体(処理)
11 | // ...
12 | return 結果;
13 | }
14 | ```
15 |
16 | ---
17 |
18 | 関数を作成するには、`function` キーワードを使います。関数を呼び出すには、関数名に続けて括弧 `()` をつけます。関数には、**パラメータ**と呼ばれる変数を指定することができます。これは**関数が呼び出される際に渡される値を受け取るためのもの**です。**引数**は、**関数を呼び出す際に渡す具体的な値**です。
19 |
20 | ---
21 | Listing2:関数の呼び出し
22 |
23 | ```javascript
24 | // 関数の定義
25 | function greet(name) {
26 | console.log("Hello, " + name + "!");
27 | }
28 |
29 | // 関数の呼び出し
30 | greet("Alice"); // Hello, Alice!
31 | greet("Bob"); // Hello, Bob!
32 | ```
33 |
34 | ---
35 |
36 | 関数は処理を実行した結果を返すことができます。return キーワードを使用して、関数が返す値を指定します。これを**戻り値**と呼びます。
37 |
38 | ---
39 | Listing3:戻り値
40 |
41 | ```javascript
42 | function add(x, y) {
43 | return x + y;
44 | }
45 |
46 | let sum = add(5, 7);
47 | console.log(sum); // 12
48 | ```
49 |
50 | ---
51 |
52 | ## 8.2 無名関数とアロー関数
53 | 関数には名前がない**無名関数**と呼ばれるものもあり、これを変数に代入することができます。
54 |
55 | ---
56 | Listing4:無名関数
57 |
58 | ```javascript
59 | // 無名関数
60 | let multiply = function(x, y) {
61 | return x * y;
62 | };
63 |
64 | console.log(multiply(3, 4)); // 12
65 | ```
66 |
67 | ---
68 |
69 | ## 8.3 アロー関数
70 | **アロー(allow:矢印)関数**は、ES6(ECMAScript 2015)で導入された新しい関数の構文です。アロー関数は通常の関数よりも簡潔であり、**主に無名関数として使われます**。以下に Listing4 の無名関数をアロー関数に書き換えたものを示します。
71 |
72 | ---
73 | Listing5:アロー関数
74 |
75 | ```javascript
76 | // 無名関数
77 | const multiply = (x, y) => {
78 | return x * y;
79 | };
80 |
81 | console.log(multiply(3, 4)); // 12
82 | ```
83 |
84 | ---
85 |
86 | **単一のパラメータを持つ場合、パラメータを括弧で囲む必要はありません**。また、処理ブロックを含む場合は、波括弧 `{}` を使用して複数の文をまとめることができます。
87 |
88 | ---
89 | Listing6:アロー関数2
90 |
91 | ```javascript
92 | // 単一のパラメータ
93 | const square = x => x * x;
94 |
95 | // 処理ブロックを含む場合
96 | const greet = name => {
97 | console.log("Hello, " + name + "!");
98 | };
99 | ```
100 |
101 | ---
102 |
103 | ---
104 | **演習1**
105 |
106 | Listing3 の `add` 関数をアロー関数に書き直してみましょう。
107 |
108 | ---
109 |
110 | ## 8.4 高階関数
111 | **高階関数**(Higher-Order Function)は、**他の関数を引数として受け取るか、または関数を戻り値として返す関数のこと**を指します。**JavaScript では関数が第一級オブジェクトである**ため、高階関数は非常に一般的であり、関数型プログラミングの概念をサポートしています。
112 |
113 | 以下は、高階関数の基本的な概念を示す例です。
114 |
115 | ### 8.4.1 関数を引数として受け取る高階関数
116 | ---
117 | Listing7:関数を引数として受け取る高階関数
118 |
119 | ```javascript
120 | const multiplyBy = (factor) => {
121 | // 引数として渡された関数を内部で呼び出す高階関数
122 | return (number) => {
123 | return number * factor;
124 | };
125 | }
126 |
127 | // 高階関数を使って新しい関数を作成
128 | const double = multiplyBy(2);
129 |
130 | // 新しい関数を使用
131 | console.log(double(5)); // 10
132 | ```
133 |
134 | ---
135 |
136 | この例では、`multiplyBy` という高階関数が、引数として渡された値に基づいて新しい関数を返しています。`multiplyBy(2)` を呼び出すことで、新しい関数 `double` が作成され、これが後で使われています。
137 |
138 | ### 8.4.2 関数を戻り値として返す高階関数
139 | ---
140 | Listing8:関数を戻り値として返す高階関数
141 |
142 | ```javascript
143 | const greet = (language) => {
144 | // 関数を戻り値として返す高階関数
145 | if (language === 'ja') {
146 | return (name) => {
147 | console.log('こんにちは、' + name + 'さん!');
148 | };
149 | } else {
150 | return (name) => {
151 | console.log('Hello, ' + name + '!');
152 | };
153 | }
154 | }
155 |
156 | // 高階関数を使って関数を取得
157 | const greetInJapanese = greet('ja');
158 | const greetInEnglish = greet('en');
159 |
160 | // 取得した関数を使用
161 | greetInJapanese('太郎'); // こんにちは、太郎さん!
162 | greetInEnglish('John'); // Hello, John!
163 | ```
164 |
165 | ---
166 |
167 | この例では、`greet` という高階関数が、引数として渡された言語に基づいて異なる挨拶のための関数を返しています。
168 |
169 | 特に React や Next.js では、関数を戻り値として返す高階関数を定義することがコンポーネントの定義と等価になります。少し難しい概念ですが、JavaScript の強力な文法を見事に利用したものですので、身につけておいて損はないでしょう。
--------------------------------------------------------------------------------
/phase2/handouts/README.md:
--------------------------------------------------------------------------------
1 | # フェーズ2:JavaScript
2 | フェーズ 2 では JavaScript を勉強し、HTML に組み込んで使用する方法について学習します。
3 |
4 | ## 事前準備
5 | このフェーズでは、常に手を動かしながら学ぶことが求められるため、作業をするためのディレクトリが必要です。このフェーズの学習を始める前に、自分の作業ディレクトリに `phase2` ディレクトリを作成してください。以降、このフェーズにおける演習は `phase2` ディレクトリ内で作業するものとします。また特に断りのない限り、エディタには **VSCode** を使用するものとします。
--------------------------------------------------------------------------------
/phase3/handouts/1-はじめに.md:
--------------------------------------------------------------------------------
1 | # 1. はじめに
2 |
3 | ## 目標
4 |
5 | 本資料では、ごく簡単なブログシステム(記事一覧/詳細の表示機能のみを備える)の作成を通じて、以下の技術を学習します。
6 |
7 | - React:Web アプリケーションの構築に必要なユーザーインターフェース(UI)フレームワーク。
8 | - Next.js:React のメタフレームワーク。使用するバージョンは v14。
9 |
10 | ## React とは
11 |
12 | Reactは、Facebook が開発する UI を構築するための JavaScript ライブラリです。主にシングルページアプリケーション(SPA)や大規模 Web アプリケーションの開発に利用されています。
13 |
14 | 公式サイト:https://ja.react.dev
15 |
16 | 以下に React の主な特徴を示します。
17 |
18 | - **コンポーネントベース**
19 | ページを「コンポーネント」と呼ばれる部品に分割して構築する。コンポーネントは再利用することが可能である。
20 | - **仮想 DOM を用いたレンダリング**
21 | 仮想 DOM を用いてレンダリングを行うことで、ページの描画を高速化する。
22 | - **JSX(JavaScript XML)**
23 | JSX と呼ばれる構文を使用して、JavaScript 内に HTML を直接記述することができる。
24 |
25 |
26 | ### 宣言的 UI
27 | React を説明する概念に「宣言的 UI」という言葉があります。従来のアプリケーションでは、状態(変数)と UI を同期するためには、変数の値に変更を加えた際に、UI を更新する操作を同時に記述する必要がありました。ところが React のように宣言的 UI を採用するフレームワークでは、状態と UI の同期はフレームワーク側で自動で行われるため、同期操作を意識して書く必要がなくなります。(難しい概念なので、そうしたものがある程度で抑えておけば大丈夫です)
28 |
29 | ## Next.jsとは
30 |
31 | Next.js は、Vercel が開発する React をより高次に発展させたメタフレームワーク(メタ=「高次の」)です。すなわち、React を扱いやすくするために存在する、React を包含した最強フレームワークが Next.js の立ち位置である、といったイメージです。
32 |
33 | 公式サイト:https://nextjs.org
34 |
35 | Next.js は、React が提供しない次の機能をサポートします。
36 |
37 | - ページ や API のルーティング
38 | - データのキャッシュ
39 | - SSR, SSG(後述)
40 |
41 | ### MPA, SPA, SSR, SSG
42 |
43 | 次の用語は、近年の Web アーキテクチャに頻出の用語です。どれも一長一短であり、サイトの特徴や流行に合わせて使い分けられると良いと思います。
44 |
45 | - **MPA(Multiple Page Application)**
46 | 従来の Web サイトの形態。ページ遷移するとサーバは HTML ファイルを返す。
47 | - **SPA(Single Page Application)**
48 | 単一のページで Web サイトを構築する技術。必要に応じて追加でデータのみをダウンロードする。ページ遷移が発生しないのでスムーズ。
49 | - **SSR(Server Side Rendering)**
50 | SPA は初回レンダリングが遅いという欠点があった。これを解消するために、初回ロード時にクライアント(手元の端末)で行っていたレンダリング処理を、サーバ側で行う。
51 | - **SSG(Static Site Generation)**
52 | SSR ではアクセスの度にサーバ側でレンダリングを行う必要があった。これをビルド時に行ってしまうことで、さらなる速度の向上を目指す。更新頻度が少ない Web サイト(ブログ等)に推奨される。
53 |
54 | SPA と MPA に関しては、下記ページで解りやすく図解されています。
55 | [SPAとMPAって何が違うの?SPAにしたほうがいい? - やわらかVue.js](https://scrapbox.io/vue-yawaraka/SPA%E3%81%A8MPA%E3%81%A3%E3%81%A6%E4%BD%95%E3%81%8C%E9%81%95%E3%81%86%E3%81%AE%EF%BC%9FSPA%E3%81%AB%E3%81%97%E3%81%9F%E3%81%BB%E3%81%86%E3%81%8C%E3%81%84%E3%81%84%EF%BC%9F)
56 |
--------------------------------------------------------------------------------
/phase3/handouts/2-基本.md:
--------------------------------------------------------------------------------
1 | # 2. 基本
2 |
3 | ## 目標
4 |
5 | 手を動かしながら React/Next.js の基礎について習得を目指します。
6 |
7 | ## 環境構築
8 |
9 | 今回は、本リポジトリの phase3/samples にテンプレートを記載したため、こちらを利用します。
10 |
11 | 以下のコマンドを実行して、Next.js の実行に必要なパッケージをインストールします。
12 | この操作は初回のみ行います。
13 |
14 | ```bash
15 | git clone git@github.com:ZDK-UTsukuba/ipc-web-training-2024.git
16 | cd ipc-web-training-2024/phase3/samples/repo
17 | yarn
18 | ```
19 |
20 | 続いて、Next.js のサーバを起動します。以下のコマンドを実行した後、適当な Web ブラウザを立ち上げて http://localhost:3000 にアクセスします。
21 |
22 | ```bash
23 | yarn run dev
24 | ```
25 |
26 | 備考
27 |
28 | - 最初からプロジェクトを構築する際は、[create-next-app](https://nextjs.org/docs/pages/api-reference/create-next-app) 等のコマンドを利用します。(今回は実行する必要はありません)
29 |
30 | ## ページの変更
31 |
32 | `/src/app` 以下に含まれる `page.js` はページを表します(詳細は後述)。今回は、このページに記事一覧画面を実装します。
33 |
34 | 中身を開くと、JavaScript の中に HTML のような記述が含まれていることがご理解いただけると思います。これが JSX です。
35 | JSX を含む関数は「関数コンポーネント」と呼ばれます。
36 | 最終的に、return 文によって返された戻り値がブラウザに表示されます。
37 |
38 | 初期状態では Hello World が表示されているので、これを*リスト 1* の通り「記事一覧」に変更して保存します。
39 | ホットリロードと呼ばれる機能により、ページをリロードしなくてもが表示が切り替わるはずです。
40 |
41 | ```jsx
42 | const Page = () => {
43 | return (
44 |
45 | 記事一覧
46 |
47 | );
48 | }
49 |
50 | export default Page;
51 | ```
52 | *リスト 1:Hello World を記事一覧に変える*
53 |
54 | ## 記事一覧の表示
55 |
56 | ### fetch
57 |
58 | 記事一覧を生成するために、[fetch](https://developer.mozilla.org/ja/docs/Web/API/Fetch_API) 関数を利用して JSON(JavaScript Object Notation)データを取得します。取得するデータの URL は以下の通りです。
59 | https://raw.githubusercontent.com/ZDK-UTsukuba/ipc-web-training-2024/master/phase3/samples/data/index.json
60 |
61 | このデータの構造は、id, title, date から構成される配列です。
62 |
63 | ```json
64 | [
65 | {
66 | id: "id",
67 | title: "タイトル"
68 | date: "最終更新日(null の可能性がある)"
69 | },
70 | ...
71 | ]
72 | ```
73 |
74 | `page.js` を *リスト 2* の通りに書き換え、fetch 関数を追加します。fetch 関数は非同期で実行されるため、await を付ける必要があります。したがって、Page 関数に async を付与します。この fetch はサーバサイドで実行されます。
75 |
76 | ```jsx
77 | const Page = async () => {
78 | // index.json を読み込む
79 | const url = "https://raw.githubusercontent.com/ZDK-UTsukuba/ipc-web-training-2024/master/phase3/samples/data/index.json";
80 | const response = await fetch(url);
81 | const json = await response.json();
82 |
83 | return (
84 |
85 | 記事一覧
86 |
87 | );
88 | };
89 |
90 | export default Page;
91 | ```
92 |
93 | *リスト 2:fetch の実行*
94 |
95 | ### map
96 |
97 | 読み込んだ記事一覧を表示するために、main 要素を*リスト 3* の通りに書き換えます。ここでは次の知識が要求されています。
98 |
99 | - JSX 中にJavaScript の記述を含める場合は中括弧 `{}` で囲う。
100 | - 属性は `attr="foo"` と記述するとそのまま文字列を指定する。`attr={foo}` と記述すると JavaScript の式として解釈される。
101 | - 要素を反復するには map 等の[高階関数](https://zenn.dev/jboy_blog/articles/e5d20e2875aa55)を利用する。for 文はほとんど使用しない。
102 | - 反復する要素には key 属性を必ず付与する。属性値にはユニークな値を使用する。今回は、id がユニークな値であると想定している。
103 |
104 | ```jsx
105 | import Link from "next/link";
106 |
107 | const Page = async () => {
108 | //省略
109 |
110 | return (
111 |
112 |
113 | {json.map((item) => (
114 | -
115 | {item.title}
116 |
117 | ))}
118 |
119 |
120 | )
121 | };
122 |
123 | export default Page;
124 | ```
125 |
126 | *リスト 3:記事一覧の表示*
127 |
128 | ### next/link
129 |
130 | Next.js で自サイト内にリンクを貼る場合は、[next/link](https://www.google.com/search?q=next%2Flink&oq=next%2Flink&gs_lcrp=EgZjaHJvbWUyCQgAEEUYORiABDIQCAEQRRgTGCcYOxiABBiKBTIHCAIQABiABDIHCAMQABiABDIHCAQQABiABDIHCAUQABiABDIGCAYQRRg8MgYIBxBFGDrSAQcyNzlqMGo5qAIAsAIA&sourceid=chrome&ie=UTF-8) から Link コンポーネントを import して使用します。a 要素は外部サイトへのリンクにのみ使用します。
131 |
132 | ### 三項演算子や条件付きレンダ
133 |
134 | JSX の記述には以下の演算子が頻出します。
135 | - **三項演算子**(`A ? B : C`)
136 | もし A ならば B、A でなければ C を返す
137 | - **論理積演算子**(`A && B`)
138 | もし A ならば B、そうでなければ A を返す
139 | - **null 合体演算子**(`A ?? B`)
140 | もし A が null でなければ A null ならば B を返す
141 |
142 | 例えば、記事一覧に最終更新日を「(最終更新:${date}」と表示する要件を加えます。最終更新日は JSON 中の date に相当しますが、date は null の可能性を有します。その際「(最終更新:null)」と不格好に表示されることを防ぐため、date の値が null でない場合のみ、括弧部分を表示するようにしたいです。
143 |
144 | この場合は、上述の論理積演算子を用いて、条件付きレンダを記述します。`page.js` を リスト 4 の通りに更新します。もし date が null の場合は [falsy](https://developer.mozilla.org/ja/docs/Glossary/Falsy) と評価されるため、「(最終更新…)」の部分は表示されません。
145 |
146 | ```jsx
147 | import Link from "next/link";
148 |
149 | const Page = async () => {
150 | //省略
151 |
152 | return (
153 |
154 |
155 | {json.map((item) => (
156 | -
157 | {item.title}{item.date && `(最終更新:${item.date})`}
158 |
159 | ))}
160 |
161 |
162 | )
163 | };
164 |
165 | export default Page;
166 | ```
167 |
168 | *リスト 4:最終更新日の表示*
169 |
170 | 備考
171 |
172 | - *リスト 4* の記述は、三項演算子を用いて以下の通りに記述することもできます。(余裕があれば試してみてください)
173 |
174 | ```jsx
175 | date ? `(最終更新:${date})` : ""
176 | ```
177 |
--------------------------------------------------------------------------------
/phase3/handouts/3-コンポーネント.md:
--------------------------------------------------------------------------------
1 | # 3. コンポーネント
2 |
3 | ## 目標
4 |
5 | コンポーネントと、React Hooks やイベントハンドラを扱います。
6 | また、サーバ/クライアントコンポーネントの違いを理解します。
7 |
8 | ## コンポーネントの分割
9 |
10 | React の特徴であるコンポーネントに触れてみます。
11 | あるまとまった機能をコンポーネントとして切り出すことで、ソースコードの肥大化を防いだり、多人数での開発を簡便化したりすることができます。
12 |
13 | ### コンポーネントの定義
14 |
15 | `/src/components` ディレクトリを新たに作成し、直下に `ListItem.js` を作成します。ファイルには*リスト 5* を記述します。
16 |
17 | ListItem が受け取る引数は props と呼ばれ、コンポーネント間で情報を受け渡す際に使用されます。
18 | コンポーネントを呼び出す際には、属性として値を渡します。
19 |
20 | ```jsx
21 | import Link from "next/link";
22 |
23 | const ListItem = ({ id, title, date }) => {
24 | return (
25 |
26 |
27 |
28 | {title}
29 |
30 |
31 | {date && 最終更新:{date}
}
32 |
33 | );
34 | };
35 |
36 | export default ListItem;
37 | ```
38 |
39 | *リスト 5:ListItem.js*
40 |
41 | 備考
42 |
43 | - コンポーネントは `/src/components` 以下に配置する場合が多いですが、App Router の導入によってその必要性は薄れつつあります。
44 | - サンプルのように、[分割代入](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)を使用すると `props.id` のように記述する必要がなくなり便利です。
45 |
46 |
47 | ### コンポーネントの呼び出し
48 |
49 | `ListItem.js` を `/src/app/page.js` から呼び出します。
50 | next/link は Page コンポーネントでは最早使用していないため、import から削除します。
51 |
52 | `page.js` の変更後のコードを*リスト 6* に示します。
53 |
54 | ```jsx
55 | import ListItem from "@/components/ListItem";
56 |
57 | const Page = async () => {
58 | // 省略
59 |
60 | return (
61 |
62 | 記事一覧
63 |
64 | {json.map((item) => (
65 |
71 | ))}
72 |
73 |
74 | );
75 | };
76 |
77 | export default Page;
78 | ```
79 |
80 | *リスト 6:page.js*
81 |
82 | 備考
83 |
84 | - create-next-app の標準設定で `@/` は `/src/` に対応するように設定されているため、`@/components/...` は `/src/components/...` を指します。
85 |
86 | ### まとめ
87 |
88 | 一連の変更により、「リンク先の内容を表示する」部品を ListItem コンポーネントとして切り出すことができました。
89 |
90 | この例ではコンポーネントのサイズが小さいため、分割する必要はあまり感じないかもしれません。しかしながら、アプリケーションの規模が大きくなり、より複雑な UI やロジックを有するようになった場合は、適切なサイズでコンポーネントに分割していくことで、その恩恵を享受することができます。
91 |
92 | ## 検索機能の実装
93 |
94 | 簡単な検索機能を実装してみます。テキストボックスを設け、キーワードが入力された際にはマッチする記事のみを表示するように変更します。
95 |
96 | ### サーバコンポーネント、クライアントコンポーネント
97 |
98 | Next.js 13 / React 18 から登場した概念に [React Server Components](https://nextjs.org/docs/app/building-your-application/rendering/server-components)(RSC)が存在します。RSC はサーバサイドで実行され、対照となる概念のクライアントコンポーネント(CC)はクライアントサイドで実行されます。
99 | 最近の Next.js で標準的に使用される App Router と呼ばれる機構では、明示的に指定しない限りコンポーネントは RSC として処理されます。
100 | RSC 内に CC を記述することはできますが、CC 内に RSC を記述することはできません。
101 |
102 | 基本的には RSC に寄せていく方針で間違いありませんが、次に代表される要件を含む場合は、RSC では制限が掛かるため CC として指定する必要があります。
103 |
104 | - ユーザの動作(クリック等)に合わせて(ページ遷移以外の)インタラクションを起こす
105 | - CSS では表現できない、動的な表現を加える
106 |
107 | ### 検索ボックスを作る
108 |
109 | 今回の「テキストボックスに入力されたキーワードにマッチする記事のみを抽出する」といった処理も、CC で表現すべき内容であると考えます(厳密には RSC でも表現可能ではありますが)。ただし、fetch の部分は RSC として実行したいため、以下の構成を採用します。
110 |
111 | | ファイルパス | RSC or CC、備考 |
112 | | --- | --- |
113 | | `/src/app/page.js` | RSC、Form.js を呼び出す |
114 | | `/src/components/Form.js` | CC、ListItem.js を呼び出す |
115 | | `/src/components/ListItem.js` | CC |
116 |
117 | そのコンポーネント**以下**が CC であると宣言するには、冒頭に [use client ディレクティブ](https://ja.react.dev/reference/react/use-client)(`"use client";`)を記述します。CC の子孫コンポーネントは自動で CC として認識されるため、RSC と CC の境界である Form.js にのみ use client ディレクティブを記述すれば OK です。
118 |
119 | `Form.js` には*リスト 7* の内容を記載します。
120 |
121 | ```jsx
122 | "use client";
123 |
124 | import { useState } from "react";
125 | import ListItem from "./ListItem";
126 |
127 | const Form = ({ items }) => {
128 | // キーワードを保持
129 | const [keyword, setKeyword] = useState("");
130 | // フィルタリング結果を保持
131 | const [filteredItems, setFilteredItems] = useState(items);
132 |
133 | // 検索を実行
134 | const search = (e) => {
135 | e.preventDefault();
136 | setFilteredItems(
137 | keyword.length > 0
138 | ? items.filter((item) => item.title.includes(keyword))
139 | : items
140 | );
141 | };
142 |
143 | return (
144 | <>
145 |
154 | {filteredItems.map((item, index) => (
155 |
161 | ))}
162 | >
163 | );
164 | };
165 |
166 | export default Form;
167 | ```
168 |
169 | *リスト 7:Form.js*
170 |
171 | 備考
172 |
173 | - fetch を RSC で実行すると Next.js 側で[キャッシュ](https://nextjs.org/docs/app/building-your-application/caching)されるため、パフォーマンスの改善や重複した API 呼び出しの排除が期待されます。
174 | - fetch を CC で実行する場合は、[useEffect](https://ja.react.dev/reference/react/useEffect) 等の Hooks を用いて過剰な呼び出しを抑制する必要があります。
175 | - ListItem 要素に与える key を `item.id` から `index` に変更しています。フィルタリングを実行した際に、id を指定すると表示が重複するバグが生ずることが要因です。
176 |
177 | ### useState
178 |
179 | *リスト 6* で特筆すべきは [`useState`](https://ja.react.dev/reference/react/useState) です。これは [React Hooks](https://ja.react.dev/reference/react/hooks) と呼ばれる仕組みに則って、コンポーネント内の状態を管理するために使用します。
180 |
181 | 冒頭で述べたように、React は宣言的 UI を採用するため、状態を管理するには通常の変数(`let foo = "bar"`)などではなく、useState 等の専用の関数を使用する必要があります。こうした React の便利機能を関数として押し込めたものを React Hooks と呼びます。
182 |
183 | useState は戻り値として、状態の値と、状態を更新するための関数を返します。これらは分割代入を用いて `[foo, setFoo]` といった命名で使用することが多いです。useState の使用例を以下に示します。(このコードを追記したり、実行したりする必要はありません)
184 |
185 | ```jsx
186 | // count の初期値に 0 をセット
187 | const [count, setCount] = useState(0)
188 |
189 | // setCount で値をセット
190 | // prev には現在の値(初期状態では 0)が入る
191 | // prev に 1 を足した値をセットするので、更新後の値は 1 となる
192 | setCount((prev) => prev + 1)
193 | ```
194 |
195 | ### イベントハンドラ
196 |
197 | ボタンを押したり、テキストボックスに文字を入力したりすると[イベント](https://developer.mozilla.org/ja/docs/Learn/JavaScript/Building_blocks/Events)が発生します。
198 | このイベントを補足する関数をイベントハンドラと呼びます。
199 |
200 | React では、属性に onChange, onClick, onSubmit 等のイベントを指定し、その値に関数(イベントハンドラ)を指定します。
201 | イベントハンドラの記述例を以下に示します。
202 |
203 | ```jsx
204 | // ボタンのクリック時にアラートを表示
205 |