Reactのキャッチアップが必要になったので公式 を一通り読んだことをまとめました。 自分用のメモなので間違い、分かりにくいところがたくさんあると思います。
Hello World
Reactを触る上での最低限のポイント。
let
、const
で変数を定義する(var
と等価)- クラスメソッドの定義の間にカンマは不要
class MyClass { method1() { // メソッドの定義 } //ここのカンマが不要 method2() { // メソッドの定義 } }
比較的新しいJavaScriptの構文
メソッド内の
this
の値に注意- オブジェクト指向の言語ではメソッド内の
this
はそのメソッドが属するオブジェクト自体を指すこと - JavaScriptではメソッドの呼び出し方によって
this
の値が変わることがある
- オブジェクト指向の言語ではメソッド内の
アロー関数
function
よりも短く書けるx => x * 2
はfunction(x) { return x * 2; }
と同じ- 関数内の
this
を持たない this
は外部メソッドの値を保持する
const obj = { name: 'John', regularFunction: function() { console.log(this.name); }, arrowFunction: () => { console.log(this.name); } }; obj.regularFunction(); // 出力: John obj.arrowFunction(); // 出力: undefined
JSXの導入
JSXについて。
// 丸括弧で囲む return ( <div> <h1>Hello, World!</h1> <p>Welcome to React.</p> </div> );
- コンパイル後はJavaScriptオブジェクトに変換される
- if文の条件式、引数などに使える式である
- 文字列リテラルは
""
、''
で加工 - HTMLの属性名はキャメルケース
- HTMLタグの要素が空の場合は
/>
で閉じれる - 描画前に値はエスケープされる(XSS対策済み)
- Babelでコンパイルされる
- JSXをコンパイルしたものをReact要素と呼ぶ
- React要素を元にDOMを描画する
要素のレンダー
描画に関するDOM関連の基礎知識。
DOMとReact要素
- DOM
- ブラウザが提供する実際のHTML要素
- 操作コストが高い
- React要素
- Reactが提供する仮想的な要素
- プレーンなJavaScriptオブジェ区tお
- 仮想DOM
- DOMと同様の階層構造を持つ
- 操作コストが低い
- React DOMを使用してDOMに変換する
- DOMとの差分のみを更新する
- DOM
React DOMのルートは
id="root"
- ルートDOMノード
- SPAはルートDOMノードは1つだけ
ReactDOM.createRoot()
はルートDOMノードに描画するルートオブジェトを作成する- ルートオブジェクトがAPIとして
render
メソッドを用意してくれる
- ルートオブジェクトがAPIとして
- React要素はいミューダブル(あとから変更できない)
コンポーネントとprops
React特有のコンポーネント、propsについて。
-
- 概念的にJavaScriptの関数に似ている
props
を受け取り、React要素を返す
JavaScriptの関数でもコンポーネントは定義できる(関数コンポーネント)
- コンポーネント定義の2つの方法
//関数コンポーネント function Welcome(props) { return <h1>Hello, {props.name}</h1>; } //クラスコンポーネント class Welcome extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } }
<コンポーネント名 />
で描画するコンポーネントを呼び出せるprops
の値は変更しないprops
は読み取り専用
stateとライフサイクル
状態管理に関する基礎知識。
クラスコンポーネント(
class クラス名 extends ...
)内のコンストラクタは必ず親クラスのコンストラクタを呼び出す必要がある(super(props);
)マウント
アンマウント
- コンポーネントがDOMから削除される時のプロセス
- リソースの解放、イベント解除などが行われる
- ライフの最後のフェーズ
- アンマウント時に特定の処理を行うには
componentWillUnmount
を使う
state
は直接変更しないstate
を変更する場合はsetState()
を使うsetState
はコンストラクタ内で行う
state
の更新はあいまい- 非同期に更新される場合がある
setState()
は現在のstate
に値をマージするprops
でのデータフローは単一方向- 親から子(下のコンポーネントにのみ影響する)
イベント処理
状態を変更する際のイベント処理について。
Reactのイベント処理
- DOM要素のイベント処理と似ている
- イベント名はキャメルケース
- JSXのイベントハンドラは文字列ではなく関数を渡す
- クリックイベントでfalseを返すには
preventDefault
を呼び出す
this
の値はメソッドがどのオブジェクトに属しているかによって変化する- メソッド内での
this
は当メソッドが所属しているオブジェクトを参照する - JSX内の
this
の扱いには注意する- 参照するオブジェクトを明示的に
bind
する必要がある
- 参照するオブジェクトを明示的に
- メソッド内での
bind
とはthis
が参照するオブジェトを指定するための処理コールバック関数をアロー関数で定義することで
this
が正しく参照される- アロー関数の記述を見つけたら
this
の参照先に注意する
- アロー関数の記述を見つけたら
onClick
で呼び出すコールバックメソッドのthis
の扱いに注意bind
でthis
の参照先を指定する- アロー関数を使い
this
の参照先を明示する
Reactではクリックイベントが発生すると自動でイベントオブジェクトが自動生成される
- イベントオブジェクトには次のようなものが含まれている
target
: イベントが発生した要素type
: イベントの種類currentTarget
: イベントハンドラがバインドされている要素
- イベントオブジェクトでユーザーの操作に関する情報を取得できる
条件付きレンダー
render
関連。
render
から処理を追い始めるのが良いrender
、coustructor
、イベントハンドラに注目して読むと処理の大まかな流れを読めるJSX内で
{}
を使うと演算子、式を含めることができるJavaScriptでの‘
condition ? true : false
はRubyの三項演算子と同じコンポーネントの再描画のトリガー
render
がnull
を返してもコンポーネントのライフサイクルは影響されない- 表示自体は非表示になる
- ライフサイクルメソッドは実行される
ライフサイクル
ライフサイクルメソッドは必ず関連して動作している訳ではない
リストとkey
リストの描画時の注意点。
- 要素のリスト項目の作成時には各要素にユニークなキー属性を付ける必要がある
- 再描画時にリスト要素の一位正を追跡できないため要素の順番を正確に反映できない
- パフォーマンスの低下
//要素のリスト項目にキーが無い function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => <li>{number}</li> ); return ( <ul>{listItems}</ul> ); } //要素のリスト項目にキーを追加 function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => <li key={number.toString()}> {number} </li> ); return ( <ul>{listItems}</ul> ); }
function ParentComponent() { const items = ['item1', 'item2', 'item3']; const listItems = items.map((item, index) => ( <ChildComponent key={item} item={item} /> )); return <ul>{listItems}</ul>; } function ChildComponent({ item }) { return <li>{item}</li>; }
- リスト出力時の
map()
を{}
を使ってインラインで埋め込むこともできる
フォーム
フォーム描画時のポイント。
Reactは変更される状態はコンポーネントの
state
に保持されるstate
はsetState()
メソッドでのみ更新できる
ユーザーが入力した内容、イベントを
state
に反映することでコンポーネントを制御する- ユーザーの入力をトグルにして動的に色々な処理ができる
- Rails + Reactで実装するメリット
preventDefault()
は、通常のブラウザの挙動をキャンセルし、ページ遷移やリロードを防止する- ユーザーの入力に対して独自の処理を追加する時に使用する
フォーム内の
input
タグのvalue属正をstate
と同期させることでユーザーの入力をリアルタイムにReact側に送信できる- ユーザーの入力がリアルタイムに
state
に反映される
- ユーザーの入力がリアルタイムに
フォームないの
textarea
タグもinput
と同様にvalue属性をstate
と同期させることでリアルタイムにReact側に送信できるselect
タグのvalue属性に配列を渡すことでオプションを複数表示することができる[]
を使うことでstateの持つプロパティを動的に変得ることができる(jsのComputed Property Names)
this.setState({ [name]: value });
- フォームに入力させたくない場合はvalue属性にundefinedかnullに設定すれば良い
- フォームに一度入力した後に変更不可にする場合は
disabled
属性をstate
を使って動的に変更することで実現できる
state のリフトアップ
state
を共通親に設定するリフトアップについて。
- 複数のコンポーネントの
state
を共通化したい場合は共通の親コンポーネントにstate
を移動する(stateのリフトアップ) state
のリフトアップの影響state
から計算できる値はstate
として保持しない- データの一貫性が保たれる
- データフローが明確になる
- デバッグ時にデータが追いやすい
コンポジション vs 継承
props
を子要素で呼び出す時のポイント。
props.children
は呼び出し側の子要素を子コンポーネント内で表示できる特別なプロパティ
function Sidebar(props) { return ( <div className="sidebar"> <h2>{props.title}</h2> <p>{props.description}</p> <div>{props.children}</div> </div> ); } function App() { return ( <Sidebar title="Sidebar Heading" description="This is the sidebar content."> <button>Click me</button> // props.childrenで呼び出される <p>Additional content</p> // props.childrenで呼ばれる </Sidebar> ); }
props.children
はプロパティとしてオブジェクトを渡すことでprops.children
を別名にすることができる親コンポーネントが孫コンポーネントに対してプロパティを渡したい場合は子コンポーネントを通して行う(プロパティのドリルダウン)
- Reactではコンポーネントの再利用、機能のモジュール化が推奨されている
- Reactではコンポーネント継承は不要
Reactの流儀
描画処理を追加するまでの手順。
UIを作る手順
1. JSONのデータ構造を分割して、それぞれの部分をどのReactコンポーネントとしてUIに表示するか決める(図を書いた方が分かりそう)
- 表示部分を四角く囲んで名前を付ける
- 1つのコンポーネントがデータモデルの1部分だけを表現することを意識
- 出来上がった図をリスト形式でネストさせて構造を把握する
2. データモデルを受け取りUIの描画だけを行う(ユーザーからの操作は不可)
- 表示とユーザー操作を切り離す
- この段階では
props
だけ使い、state
は使わない - 大きい枠組みから作り始めた方が楽
3. 何をstateにするか決める
- 必要になった時に
state
を元に処理を追加することを意識(不要なstateを作らない) - 何をstateにするか決める
4. stateをどのクラスに配置するか決める
- stateで表示する全てのコンポーネントを洗い出す
- 見つけたコンポーネントの共通の親コンポーネントを見つける
- 共通の親コンポーネント or そのさらに親コンポーネント がstateを持つべきか決める
- stateを持つべきコンポーネントが見つからなかったらstate保持だけのコンポーネントを作る
感想
React難しい... 今まで学習してきたなかで間違い無く一番難易度が高いと感じてます。 ただ、これを乗り越えれば苦手だったフロントエンドとも仲良くなれそうなので地道にやっていきます!