Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

第一部のreact編 #130

Merged
merged 10 commits into from
May 12, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion docs/.vitepress/sidebarConfigs/chapters/chapter1/chapter1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,15 @@ export const chapter1SidebarItems: DefaultTheme.SidebarItem[] = [
...section1SidebarItems,
...section2SidebarItems,
...section3SidebarItems,
...section4SidebarItems
...section4SidebarItems,
{
text: 'React入門',
link: '/chapter1/dicts/react/0_react-intro'
},
{
text: 'アプリを作ってみよう(React)',
link: '/chapter1/dicts/react/1_create-app'
}
]
}
]
Expand Down
221 changes: 221 additions & 0 deletions docs/chapter1/dicts/react/0_react-intro.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
# React 入門

React 編は本編を一通り終えた後に行うことを想定しているため、一部省略しています。本編が終わっていない方は先に本編を進めてください。

## React プロジェクトの作成

`~/develop`ディレクトリの中で以下のコマンドを実行してください。
```bash
$ npm create vite@latest todolist -- --template react-ts -y

Scaffolding project in /home/mehm8128/develop/todolist...

Done. Now run:

cd todolist
npm install
npm run dev

```

プロジェクトが作成できたら、`cd {プロジェクト名}`でプロジェクトのディレクトリに移動し、VSCode で開いてください。

開いたプロジェクトの中に入っている`package.json`というファイルには npm に関する様々な設定が書かれています。
この中には依存するパッケージ一覧も含まれており、以下のコマンドでそれらをインストールできます。

`$ npm i`
もしくは
`$ npm install`

```bash
mehm8128@DESKTOP-6F4C0KI ~/develop/todolist-mehm8128 (main)$ npm i

added 218 packages, and audited 219 packages in 12s

41 packages are looking for funding
run `npm fund` for details

found 0 vulnerabilities
```

テンプレートは初期状態でビルド&配信できるようになっているので、以下のコマンドを実行してブラウザで確認してみましょう。

`$ npm run dev`

```bash
mehm8128@DESKTOP-6F4C0KI ~/develop/todolist-mehm8128 (main)$ npm run dev

> [email protected] dev
> vite

Port 5173 is in use, trying another one...

VITE v5.2.10 ready in 159 ms

➜ Local: http://localhost:5174/
➜ Network: use --host to expose
➜ press h + enter to show help
```
mehm8128 marked this conversation as resolved.
Show resolved Hide resolved

この状態で、ブラウザから <a href='http://localhost:5173/' target="_blank" rel="noopener noreferrer">localhost:5173</a> にアクセスすると、以下のような画面が表示されるはずです。

![](images/0/vite-start.png)

止めるときは`Ctrl + C`で止めてください。

また、このタイミングで Git の初期化もしておきましょう。`.git`ディレクトリがプロジェクト内に存在していないので、このままだと Git 管理ができません。
```bash
$ git init
```

## React 入門

### React とは

以下のリンクから公式ドキュメントに飛ぶことができます。
[React](https://react.dev/)

日本ではよく使われているフレームワークなのですが traP ではあんまり使われておらず、使われているのは traPCollection くらいです。

### `.tsx`ファイルについて

Vue では`.vue`という拡張子でコンポーネントファイルを作成していましたが、React では`.tsx`という拡張子でコンポーネントファイルを作ることができます。

基本的には TypeScript を書いて、`return()`内に HTML(tsx, jsx)を書きます。
mehm8128 marked this conversation as resolved.
Show resolved Hide resolved


#### Sample.tsx

<<< @/chapter1/dicts/react/src/0/Sample.tsx


## React を書く準備

まず、以下の拡張機能をインストールしてください。

#### React Developer Tools

Chrome Devtool に React 向けのデバッグ機能を追加してくれます。
[React Developer Tools - Chrome ウェブストア](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=ja)


## React を書く

### React を書く

先にコードを書いてから解説を書いています。
意味がわからなくてもとりあえずコピー&ペースト or 写経しましょう。

#### ファイルの作成

`components`ディレクトリを作成し、その中に`ClickCounter.tsx`というファイルを作成します。

![](images/0/clickcounter.png)

#### ソースコードの変更

#### src/main.tsx

CSS ファイルの読み込みを削除します。

<<< @/chapter1/dicts/react/src/0/main.tsx{tsx:line-numbers}

##### src/pages/App.tsx

`ClickCounter.tsx`を読み込み、カウンターを配置します。

<<< @/chapter1/dicts/react/src/0/App.tsx{tsx:line-numbers}

cp-20 marked this conversation as resolved.
Show resolved Hide resolved
##### src/components/ClickCounter.tsx

<<< @/chapter1/dicts/react/src/0/ClickCounter.tsx{tsx:line-numbers}

以下のように動けば OK です。

![](images/0/preview.gif)

### ソースコード解説

#### src/pages/App.tsx

##### 4 行目
mehm8128 marked this conversation as resolved.
Show resolved Hide resolved

```ts
import ClickCounter from "./components/ClickCounter.tsx"
```

`ClickCounter` コンポーネントを読み込む部分です。

##### 9-23行目
mehm8128 marked this conversation as resolved.
Show resolved Hide resolved
テンプレート部分です。
React のコンポーネントは 1 つのタグの中に収まっている必要があります。
そのため、多くの場合 div タグで囲まれています。
mehm8128 marked this conversation as resolved.
Show resolved Hide resolved

##### 7 行目
mehm8128 marked this conversation as resolved.
Show resolved Hide resolved

```tsx
<ClickCounter />
```

読み込んだコンポーネントを利用しています。

#### src/components/ClickCounter.tsx

##### 4 行目

コンポーネント内で利用する変数を`useState`を用いてこのように書きます。引数には変数の初期値を与えます。
ここでは`count`という名前の変数を`number`型で定義しています(実はこの程度なら TypeScript の型推論というものが効いて、初期値の`0`から自動で`count`変数は`number`型だと推論してくれます)。
`useState`は返り値の配列の 0 番目に変数、1 番目に変数を更新するための関数が入っています。今回でいうと`count`が変数、`setCount`が変数を更新するための関数です。
React はこの`setCount`が実行されたときに、引数に与えられた値で`count`の値を更新し、表示も更新(再描画)してくれます。

```ts
const [count, setCount] = useState<number>(0)
```

参考
[useState – React](https://react.dev/reference/react/useState)
[ジェネリクス (generics) | TypeScript入門『サバイバルTypeScript』](https://typescriptbook.jp/reference/generics)

:::info
ここで`counter.js`の`countUp`を見てみましょう。

```js
const countUp = () => {
count++
const countElement = document.querySelector('#count')
countElement.innerText = '回数: ' + count
}
```

`count`変数の値を変更した後に、DOM を直接操作して回数の値を更新しています。
React では先ほど述べたように、`useState`を使うことで「値を更新」と「表示を変更」の 2 つをセットでやってくれるようになります。

:::

##### 7 行目

`return()`内では`{}`内に JavaScript が書けるので、count 変数の中身を表示しています。
mehm8128 marked this conversation as resolved.
Show resolved Hide resolved

```tsx
<div>回数: {count}</div>
```

参考: [JavaScript in JSX with Curly Braces – React](https://react.dev/learn/javascript-in-jsx-with-curly-braces)


##### 8・9 行目

ボタンが押されたイベントに対する処理を書いています。
`useState`で定義した`setCount`関数に引数を渡すことで、`count`変数の中身を更新できます。
また、`onClick`では今回のように直接 JavaScript を記述するだけでなく、`return()`外で定義した関数の呼び出しもできます。


```tsx
<button onClick={() => setCount(count + 1)}>クリック!</button>
<button onClick={() => setCount(0)}>リセット!</button>
```

参考
[イベントへの入門 - ウェブ開発を学ぶ | MDN](https://developer.mozilla.org/ja/docs/Learn/JavaScript/Building_blocks/Events)
[Responding to Events – React](https://react.dev/learn/responding-to-events)

154 changes: 154 additions & 0 deletions docs/chapter1/dicts/react/1_create-app.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# アプリを作ってみよう

## 商品リストを作ってみる

みなさんにはこの節の最後に Todo リストを作ってもらうのですが、商品リストをテーマに、Todo リストに必要な機能をピックアップしていきます。

こんな感じのを作っていきます。
![](images/1/preview.gif)

### 必要な要素を考える

上の gif のようなアプリを実現するためには何が必要か考えてみましょう。

- 商品リストのコンポーネントを作る
- 商品のリストデータを保存する
- 商品のリストデータを表示する
- 商品を追加できる
- 商品の値段が 500 円以上だったら赤くする
- 商品の値段が 1000 円以上だったら「高額商品」と表示する

こんな感じでしょうか。
それでは上から順番に実装していきましょう。

### 商品リストのコンポーネントを作る

`components`ディレクトリに`ItemList.tsx`というファイルを作成します。
![](images/1/directory.png)

#### src/components/ItemList.tsx

中身はコンポーネントに最低限必要な部分だけ書きます。

<<< @/chapter1/dicts/react/src/1/ItemListInit.tsx{tsx:line-numbers}

#### App.tsx

<<< @/chapter1/dicts/react/src/1/App.tsx{tsx:line-numbers}

表示されました。
こうすることで、後は`ItemList.tsx`の中身を書き変えればよくなります。

![](images/1/itemlist-setup.png)

### 商品のリストデータを保存する

商品リストのデータを保存するのに適当な変数の型は何でしょうか?
商品「リスト」なので配列がよさそうです。
というわけで、配列を使ってデータを保持することにします。
今は商品の追加ができないので、とりあえずダミーデータを入れておきます。

参考
[Array | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array)
[JavaScript オブジェクトの基本 - ウェブ開発を学ぶ | MDN](https://developer.mozilla.org/ja/docs/Learn/JavaScript/Objects/Basics)

<<< @/chapter1/dicts/react/src/1/ItemListItems.tsx{tsx:line-numbers}

4~7 行目は TypeScript の記法で、`Item`という型を`interface`を用いて定義しています。
そして `useState` のジェネリクスに`Item[]`を渡すことで、`items`変数を`Item`型の配列として扱えるようにしています。

参考: [インターフェース (interface) | TypeScript 入門『サバイバル TypeScript』](https://typescriptbook.jp/reference/object-oriented/interface)

### 商品のリストデータを表示する

先ほど定義したリストの情報を表示していきます。
React ではリストデータを for 文のようにループさせて表示させるには、`map`を使います。
`map` を使うときには`key`を設定しなければいけません(理由(やや難): [Rendering Lists – React](https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key))。

参考: [Rendering Lists – React](https://react.dev/learn/rendering-lists)

これを使ってデータを表示してみます。

<<< @/chapter1/dicts/react/src/1/ItemListList.tsx{tsx:line-numbers}

表示できました。

![](images/1/itemlist.png)

### 商品を追加する

フォームを使って、入力された文字を変数に格納します。
参考: [input – React](https://react.dev/reference/react-dom/components/input#controlling-an-input-with-a-state-variable)

これを使って商品を追加できるようにしてみます。

<<< @/chapter1/dicts/react/src/1/ItemListAdd.tsx{tsx:line-numbers}

参考: [アロー関数式 | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions)

できました!

![](images/1/add-item.gif)

#### 練習問題 1:商品リストに機能を追加

このままだとボタンを連打して商品の追加ができてしまいます。

- ボタンを押したら入力欄を空にする機能
- 入力欄が空だったらボタンを押しても追加されないようにする機能

を追加してみましょう。

### 商品の値段が 500 円以上だったら赤くする

条件が満たされたときだけ CSS を当てるようにしてみます。
`items`配列を展開するところで。三項演算子を用いて条件を満たしたときにだけ`className`がつくようにします。

参考: [CSS の基本 | MDN](https://developer.mozilla.org/ja/docs/Learn/Getting_started_with_the_web/CSS_basics)
参考: [条件 (三項) 演算子 - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Conditional_operator)
参考: [css-modules/css-modules: Documentation about css-modules](https://github.com/css-modules/css-modules)

<<< @/chapter1/dicts/react/src/1/ItemListRed.tsx{2,26}

そして、`src/components/ItemList.module.css`を作成して以下の内容を記入します。

<<< @/chapter1/dicts/react/src/1/ItemList.module.css{tsx:line-numbers}

![](images/1/red.png)

### 商品の値段が 10000 円以上だったら「高額商品」と表示する

ある特定の条件を満たした場合のみ、対象コンポーネントを表示するという機能を`&&`を使って実現します。もちろん、三項演算子を使っても実現できます。

参考: [Conditional Rendering – React](https://react.dev/learn/conditional-rendering)

これを使って商品の値段が 10000 円以上だったら「高額商品」と表示するという機能を実現してみましょう。

<<< @/chapter1/dicts/react/src/1/ItemListExpensive.tsx{29}

![](images/1/expensive.png)

これで商品リストが完成しました!

## Todo リストを作る

ここまで紹介してきた機能を使うことで Todo リストが作れるはずです。
頑張りましょう!

#### 練習問題 2:Todo リストを作る

Todo リストを作りましょう。

必要な機能は以下の通りです。

- タスクは未完または完了済みの状態を持つ。
- タスクはタスク名を持つ。
- 未完タスクのリストと完了済みタスクのリストが表示される。
- タスクを完了させることができる。
- タスクの追加ができる。

以上の機能が実現されていれば後は自由です。
スタイルが気になる人は CSS なども書きましょう。

## 制作物を公開する
Vue の Todo リストを公開したときと同様の方法で公開できるはずです。やってみましょう。
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chapter1/dicts/react/images/0/preview.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chapter1/dicts/react/images/1/add-item.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chapter1/dicts/react/images/1/directory.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chapter1/dicts/react/images/1/expensive.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chapter1/dicts/react/images/1/itemlist.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chapter1/dicts/react/images/1/preview.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/chapter1/dicts/react/images/1/red.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading