react.devをただ読んでいく
README
Next.jsのチュートリアルやりながら気になったreact.dev(主にLEARNの部分)をひたすら読んでいく
(チュートリアルにここ読んでおけよ〜的な指示あるのありがてぇ
)
Writing Markup with JSX
チュートリアルに「JSXは3つのルールに従って書けよ〜〜」的な部分があって、この章のリンクが挿入されていた。
Overview
- Reactがマークアップとレンダリングロジックを点在させる理由
- JSXはHTMLとどう違うのか?
- JSXで情報を表示する方法
JSX: Putting markup into JavaScript
- Webがインタラクティブになるにつれて、ロジックがコンテンツを決定
- HTML部分をJSで記述するように...
- この流れからReactはレンダリングロジックとマークアップをコンポーネント内に共存させた
- 以下の部分はMVCとの比較で考えたらわかりやすい😙
- また「サイドバーのマークアップ」「ボタンのマークアップ」のように関連性のない詳細は互いに分離されているからどちらか一方だけを変更しても安全。(変更容易性)
ボタンのレンダリングロジックとマークアップを一緒にしておくことで、編集のたびにお互いの同期をとることができます
- コンポーネントはマークアップを表現するためにJSXという構文拡張を利用
- 少し厳格なルールの元で動的な情報も表示できる
Converting HTML to JSX
- JSXを理解するには実際にHTMLをJSXに変換してあげるとええで〜👍
- 例えば以下はうまくいかんぜよ😱
The Rules of JSX
- Return a single root element
- Close all the tags
- camelCase all most of the things!
-
なぜ複数のJSXタグはラップされるのか?
- JSXは最終的にHTMLとして表示されるけど、裏側ではBabelによってReact要素=プレーンなJSオブジェクトに変換されている
- 関数から例えば複数のオブジェクトが返却されるには、それらを配列でラップする必要がある..
- この配列のラップの役割を担っているのだ!!!
-
タグを明示的に閉じる
- 自己閉鎖タグは
<img />
として、<li>のような折返しタグも必ず閉じる
- 自己閉鎖タグは
-
キャメルケース使えよ!
- 自作コンポーネント作りたい場合は属性を変数として保持したいケースがでてくる
- Mantineでいうところのsx?
- そのためJSの変数規則に従っておいたほうがその辺うまくいく
- 自作コンポーネント作りたい場合は属性を変数として保持したいケースがでてくる
-
コンバーター使えば便利にhtml to ●●ができるぜ!!
Recap
- JSXの存在理由=
Reactコンポーネントでは、レンダリングロジックとマークアップが関連しているため、一緒にまとめている。その際にJSXを用いてマークアップしていく
- コンポーネントでの使い方=
3つのルールに沿って基本書いていこう。必要となればコンバーターも
Your First Component
チュートリアルでコンポーネントについて学んどけよ!!って出てきたので読んできます。
Overview
- コンポーネントとは?
- Reactアプリケーションでコンポーネントが果たす役割とは
- 初めてのReactコンポーネントの書き方
Components: UI building blocks
- Writing Markup with JSXでもあったけど、Reactでは、マークアップ、CSS、JavaScriptを組み合わせて、アプリの再利用可能なUI要素である「コンポーネント」を作成できる!
- これの利点としては、「再利用性」で規模の大きなプロジェクトになるにつれてどんどん再利用していけるようになり、開発速度↑
Defining a component
-
Reactのコンポーネントは、基本的にはJavaScript関数
-
コンポーネントの作り方
1.コンポーネントをエクスポート
2. 関数を定義
3. マークアップの追加 -
エクスポートに関してはImporting and Exporting Componentsを読め!
-
関数名は大文字やで!
- Babelの対象となるには大文字から始まるタグじゃないと認識されないらしい...
-
JSX使ってマークアップしてけよ!
- 一行だと()いらんで
- 複数行だと()必要。()なかったら無視されるで
return <img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />;
Using a component
- コンポーネントは通常の関数なので、複数のコンポーネントを同一ファイル内に保持できる
- コンポーネントが比較的小さかったり、互いに密接に関連しあっている場合にGood
- ファイルが混雑してきたら他ファイルに移そう
- 関数をネストさせることも当然可
- ただコンポーネントの定義自体をネストさせることはやばいぜ!!
export default function Gallery() {
// 🔴 Never define a component inside another component!
function Profile() {
// ...
}
// ...
}
- これはバグの原因にもなるし、実行速度がめちゃんこ遅い
- Different components at the same position reset state参照
- Stateの保持とリセットの概念とめっちゃ結びついている
※ルートコンポーネントについて
- CRAなどでセットアップしたCSR前提のReactアプリケーション(既存のHTMLページにインタラクティブ性を追加)だと空のHTMLファイルを返し、ページ管理をReactに任せるといったイメージ
- ページ全体に単一のコンポーネントを使用している...とかではなく、ただのルートコンポーネント(Reactを必要な分だけ使うというイメージ)
-
Reactベースのフレームワーク(Next.js/Remix)だと、ページ全体に単一のコンポーネントを使用しReactコンポーネントからHTMLを自動作成している
- そのためJSダウンロード前にページ表示可能
- 以下の話っすな
Recap
- Reactでは、再利用可能なUI要素であるコンポーネントを作成
- Reactアプリでは、UIのすべてのピースがコンポーネントになってる
- Reactコンポーネントは、ただのJavaScriptの関数
- 常に大文字で始まる。
- JSXのマークアップを返します
Importing and Exporting Components
Overview
- ルートコンポーネントファイルとは
- コンポーネントのインポート、エクスポート方法
- デフォルトと名前付きインポートおよびエクスポートを使用する場合
- 1つのファイルから複数のコンポーネントをインポートおよびエクスポートする方法
- コンポーネントを複数のファイルに分割する方法
The root component file
- CRAだとApp.jsにルートファイルがある
- Next.jsだとファイルシステムルーティングを採用しているので、ルートコンポーネントはページごとに異なるもの
Exporting and importing a component
- default export と named export
Syntax | Export statement | Import statement |
---|---|---|
Default | export default function Button() {} | import Button from './Button.js'; |
Named | export function Button() {} | import { Button } from './Button.js'; |
- ファイルが1つだけのコンポーネントをexportするときはdefault、複数コンポーネントと値をexportする際はnamed exportする場合が多い
- あとはどちらの手法にせよ、コンポーネント名とファイル名にはちゃんとこだわる
Exporting and importing multiple components from the same file
- ファイルには、default exportは1つしかありませんが、名前付きのエクスポートは多数持つことができる
- 時と場合によってはdefault exportとnamed exportを混ぜて使用する
- チームによってこの規則は柔軟に
Render and Commit
- Reactにおけるレンダリングの意味
- Reactがコンポーネントをレンダリングするタイミングと理由
- コンポーネントを画面に表示する手順
- レンダリングが常にDOMを更新するとは限らない理由
- このあたり。こんな感じで最初に概要説明してくれるのほんと助かるよな。
- 最初はトリガー→レンダー→コミットのくそわかりやすい例
- たしかにレストランで例えるのは超わかりやすい
- Reactは客からリクエスト(注文)を受け入れて、注文を運ぶウェイター
- 主にUIを構築するには以下の3Stepで成り立つ
- レンダーをトリガーする(客の注文を厨房に運ぶ)
- コンポーネントのレンダリング(厨房でのオーダー準備)
- DOMにコミット(注文をテーブルに運ぶ)
- トリガーは2パターンで発生
- 初回レンダリング
- これは基本的にはフレームワークなどで隠蔽されがちだけど、ターゲット(客)のDOMノードでcreateRootを呼び出して、そのコンポーネントでrenderメソッドで呼び出せば完了
- stateの更新時
- set関数で状態を更新することで、レンダリングをトリガーできる
- コンポーネントの状態を更新すると、自動的にレンダリングのキューに入る
- 初回レンダリング
- レンダリング
- レンダーがトリガーされると、Reactはコンポーネント(厨房)を呼び出して画面に何を表示するかを決定する。レンダリングとは、Reactがコンポーネントを呼び出すこと!!
- 初回レンダリング時に、ルート・コンポーネントを呼び出す
- それ以降のレンダリングでは、Reactは状態の更新がレンダリングのトリガーとなった関数コンポーネントを呼び出す
- ここで重要なのは以下
更新されたコンポーネントが他のコンポーネントを返したら、Reactはそのコンポーネントを次にレンダリングし、そのコンポーネントも何かを返したら、そのコンポーネントを次にレンダリングする、という具合だ。このプロセスは、ネストされたコンポーネントがなくなり、Reactが画面に何を表示すべきかを正確に把握するまで続けられる。
- またあくまで再レンダリングが起こるのは、前回のレンダリング以降に変更されたプロパティがある場合のみ
- そしてその場合は、ただどこに変更があったのか?を計算するだけ
- その情報を使ってなにかするのは、コミットフェーズ以降
- レンダーがトリガーされると、Reactはコンポーネント(厨房)を呼び出して画面に何を表示するかを決定する。レンダリングとは、Reactがコンポーネントを呼び出すこと!!
- ラストがコミット
- コンポーネントをレンダリング(呼び出し)後に、ReactはDOMを変更する
- 初回レンダリングでは、作成されたDOMノードをReactはappendChildを利用して画面に配置する
- 再レンダリングでは、Reactは必要最小限の操作(レンダリング中に計算される)を適用して、DOMを最新のレンダリング結果と一致させる
- このあたりの必要最小限の操作を適用させているのが、仮想DOMっぽいな
https://zenn.dev/mizchi/books/0c55c230f5cc754c38b9/viewer/a1df9bda190861e0455f
- ペイント
- ラストで、ReactがDOMを更新した後、ブラウザは画面を再描画する。このプロセスはレンダリングとごっちゃになりやすいので「ペイント」と呼ばれる
Referencing Values with Refs
- 個人的には以下が新しい発見
レンダリング中にref.currentを読み書きしないでください。これにより、コンポーネントを予測しにくくなります。
Manipulating the DOM with Refs
- この章は結構おもろいな。
- ざっと読んだけど、「DOMノードへの参照を下位コンポーネントへ転送する」あたりの話は参考になった
- あとは「Reactがrefをアタッチするとき」の部分もクソおもろい
- 以下引用
Reactがrefsをアタッチするとき
一般的に、レンダリング中にrefにアクセスすることは避けたい。DOMノードを保持するrefも同様です。最初のレンダリングでは、DOMノードはまだ作成されていないため、ref.currentは nullになります。また、更新のレンダリング中は、DOMノードはまだ更新されていません。つまり、それらを読み取るには時期尚早なのだ。Reactはコミット時にref.currentを設定します。DOMを更新する前に、Reactは影響を受けるref.currentの値をnullに設定します。DOMを更新した後、Reactは直ちにそれらを対応するDOMノードに設定します。
通常は、イベントハンドラからrefにアクセスします。refを使って何かをしたいが、そのための特定のイベントがない場合、エフェクトが必要になるかもしれません。エフェクトについては、次のページで説明します。
- つまりコミット時にref.currentは設定されるから、コミット後に実行されるイベントハンドラ内などで参照すべき。