Skip to content

Commit 8e884cc

Browse files
committed
宣言的, 命令的の説明を追加
1 parent 4ad2be6 commit 8e884cc

File tree

1 file changed

+34
-3
lines changed

1 file changed

+34
-3
lines changed

docs/4-advanced/04-react/index.mdx

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import componentRenderingVideo from "./component-rendering.mp4";
99

1010
これまで、JavaScriptによりHTML要素を操作するために、[DOM](/docs/trial-session/dom/)を用いることができることを学んできました。しかしながら、ナイーブな方法によりDOMを使用すると、アプリケーションの規模の限界がすぐにやってきます。
1111

12-
簡単なToDoアプリケーションを例に考えてみましょう。
12+
簡単なToDoアプリケーションを例に考えてみましょう。これまで学んできたDOM操作による処理の記述は、**命令的アプローチ**と呼ばれます。
1313

1414
```html title="index.html"
1515
<ul id="todos"></ul>
@@ -49,6 +49,23 @@ addTodoButton.onclick = () => {
4949

5050
**宣言的UI**は、こういった性質に着目します。より具体的に説明するのであれば、アプリケーションの状態$S$に対し、関数$f(S)$によりUIの状態を表現できるのであれば、開発者の関心を$S$の変化と$f$の定義のみに絞ることができるというわけです。
5151

52+
<div style={{textAlign: 'center'}}>
53+
54+
```mermaid
55+
flowchart LR
56+
add(["add"]):::event --> S["S"]:::state
57+
remove(["remove"]):::event --> S
58+
S --> f["f(S)"]:::ui
59+
60+
classDef event fill:#e8e8e8,stroke:#999,font-size:12px
61+
classDef state fill:#4a90d9,stroke:#2e6bb0,color:#fff
62+
classDef ui fill:#f5f5f5,stroke:#ccc
63+
```
64+
65+
</div>
66+
67+
開発者はイベント(`add``remove`)による状態の変化と、状態に対応するUIを定義します。UIの更新処理、つまり具体的なDOM操作は自動で行われます。
68+
5269
具体的なコードで確認してみましょう。先ほどのToDoアプリケーションを、宣言的UIのアプローチを用いて書き換えてみましょう。状態を追いやすいよう、TypeScriptを用いて記述します。
5370

5471
まずはアプリケーションの状態と、その状態を格納する変数を宣言します。
@@ -94,7 +111,15 @@ function removeTodo(index: number) {
94111

95112
先ほどのプログラムはうまく動作しますが、一つ問題があります。それは、`render`関数が呼ばれるたびに全ての要素が削除され、再構築される点です。一般的に、DOMに対する操作は非常にコストが高く、可能な限り減らすことがパフォーマンス改善のために有効です。
96113

97-
[React](https://ja.reactjs.org/)は、この問題を**仮想DOM**を用いて解決します。Reactは、DOMに似たデータ構造を内部的にJavaScriptオブジェクトの形式で保持し、実際に変更された部分のみを実際のDOMに反映させることで、高いパフォーマンスを実現しています。
114+
[React](https://ja.react.dev/)は、この問題を**仮想DOM**を用いて解決します。Reactは、DOMに似たデータ構造を内部的にJavaScriptオブジェクトの形式で保持し、実際に変更された部分のみを実際のDOMに反映させることで、高いパフォーマンスを実現しています。
115+
116+
:::tip[仮想DOMと差分検出]
117+
118+
Reactでは、開発者は「UIがどうあるべきか」を宣言するだけで済みます。状態が変化すると、Reactは新しい仮想DOMを作成し、以前の仮想DOMとの差分(diff)を自動的に計算します。そして、実際に変更が必要な部分のみをDOMに反映させます。
119+
120+
つまり、命令的なDOM操作を開発者の代わりにReactが行ってくれるのです。
121+
122+
:::
98123

99124
それでは、Reactを用いたプロジェクトを作成してみましょう。Viteでプロジェクトを作成しますが、`framework``React``variant``TypeScript`を選択してください。
100125

@@ -137,7 +162,7 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
137162

138163
:::tip[Non-null assertion operator]
139164

140-
`document.getElementById("root")`の直後に続く`!`記号は、TypeScriptのnon-null assertion operatorです。`document.getElementById`関数は、要素が見つからなかった場合に`null`を返すため、戻り値は`HTMLElement | null`型と定義されています。`null`である可能性がないことをプログラマが保証することをTypeScriptに伝える記号が`!`です。なお、`tsconfig.json`の設定によってはこのエラーは表示されません。
165+
`document.getElementById("root")`の直後に続く`!`記号は、TypeScriptのnon-null assertion operatorです。`document.getElementById`関数は、要素が見つからなかった場合に`null`を返すため、戻り値は`HTMLElement | null`型と定義されています。`null`である可能性がないことを開発者が保証することをTypeScriptに伝える記号が`!`です。なお、`tsconfig.json`の設定によってはこのエラーは表示されません。
141166

142167
```typescript
143168
document.getElementById("root").textContent; // Object is possibly 'null'.
@@ -146,6 +171,12 @@ document.getElementById("root")!.textContent; // OK
146171

147172
:::
148173

174+
:::tip[React.StrictMode]
175+
176+
`<React.StrictMode>`は開発環境でのみ有効になるモードで、潜在的なバグを検出するためにコンポーネントを2回実行します。これにより、コンポーネントが[純粋関数](https://react.dev/learn/keeping-components-pure)であるかどうか(同じ入力に対して常に同じ出力を返すか)をチェックできます。本番ビルドには影響しません。
177+
StrictModeのため、開発環境では`console.log`でデバックする際に2回実行されることに注意してください。
178+
:::
179+
149180
それでは、`App.tsx`を書き換えながら、Reactの動作を確認していきましょう。まずは、`App.tsx`を次のように修正します。
150181

151182
```tsx title="App.tsx"

0 commit comments

Comments
 (0)