Udemy_React入門の学習記録
Udemyの教材のセクション4,5
内容のまとめ
・プレーンなjsでよく使う記法の解説
・プレーンなjsを使ってTODOアプリを作る
JSのアロー関数
・const メソッド名 = (引数) => {関数の処理}
を メソッド名(引数)
で実行
・昔見た時よくわからなかったけど、他の言語に慣れた状態でみたらすぐ理解できた
mapについて
・Rubyのmapと同じで、each文やfor文の戻り値を変数に格納して出力することを一括で行える
const array = [1, 2, 3, 4];
const map = array.map((x) => x * 2);
console.log(map1);
// Array [2, 4, 6, 8]
getElementById
やcreateElement
やappendChild
などを使って、DOMの特定の要素を特定したり取得したり、生成することでJSで画面描写を動的に追加したり削除できる
Udemyの教材のセクション6
内容のまとめ
・Reactの基本的な構文について
・関数コンポーネントについて
・フックについて
・state管理について
JSX記法で返却するHTMLは必ず1つのタグの中に収まっていないといけない
・必ず1つのタグの親要素が外側にないといけない
・通常はdivタグ<div>
か、空タグを用いる<>
関数コンポーネント
・複数のファイルへ切り出したものを呼び出すことで処理を実行する
・その際に切り出すコンポーネントは関数の関数の形で作成するため関数コンポーネントと呼ぶ
イベントとスタイル
・ReactでイベントやスタイルをHTMLに当てることができる
・この時、どこからがjs記法かわからないので{}で囲んだ内部でjsを記述する
・cssのスタイル時では認識できた記述がjsだと認識できないところがあるので適切な記述に変換する
(-小文字
→ キャメルケース
, スタイルのプロパティのvalueは文字列で与えるなど)
Props
propsとは
・コンポーネントに対して渡す引数
・コンポーネントを動的に使用したい時に使う
使い方
・コンポーネントを呼び出す側で、引数=値
という形で呼び出す。
・コンポーネント本体は、関数を定義するところで、引数を受け取る (一般的にpropsという変数を使う)
・このpropsがオブジェクト形式のデータなので必要なプロパティを参照すれば良い
childrenの使い方
・コンポーネントの呼び出し元で、コンポーネントタグの中に記述をしたとする
・この記述は、コンポーネント側で、props.children
として取得可能 (引数で渡す必要がない)
分割代入と組み合わせる
・props. を毎度書くのは冗長なので、分割代入を定義することで関数コンポーネント中の記述をスッキリ書ける
State
useStateについて
・カウントアップなどで、現在のstateを参照する際に、Reactが提供するuseState
を用いる
userStateの使い方
- 第1引数
- jsx記法の中で参照する際は、そのまま変数名を指定したら参照できる
- 第2引数
- 第2引数は関数なので使用する時は、
引数名()
という形で使用する
- 第2引数は関数なので使用する時は、
注意点 : usertateの第二引数(set関数)は、呼ばれた瞬間にstateを更新するわけではない
- そもそも値の更新は、set関数が呼ばれると、React側がもう一度コンポーネントを上から評価してくれることで実現
- Reactは、この再評価は、set関数が呼ばれた直後にしない
- Reactがパフォーマンスよくアプリケーションを動かせるようにこのような仕組みになっている
- これをバッチ処理という
- set関数が複数あると、その数分の再評価をしないといけない
- 一気に全てのset関数を見てから一度だけ再評価をする方が効率的
- つまり、set関数が呼ばれた直後に再読み込みせずに、1つのスコープの処理が完了したタイミングで呼ぶべき
set関数の中身をアロー関数で記載
- 特定の処理の中で、現在のstateの値を参照するようにしたい場合は、↑の注意点を考慮した工夫が必要
- そのため、リアルタイムで現在のstateの値を参照するには別の工夫が必要
- この時、set関数の中身にアロー関数を用いる
- このアロー関数の引数には、useStateの第1引数が自動的に入るように設計されている (num)
- この引数を受け取ってアロー関数の内部で処理を書くと、現在のstateを参照することができる
- (一般的に、この引数は
prev
などが用いられることが多い)
import { useState } from "react";
export const App = () => {
const [num, setNum] = useState(0);
const onCclickCountUP = () => {
setNum((prev) => prev + 1);
};
return (
<>
<button onClick={onCclickCountUP}>カウントアップ</button>
<p>{num}</p>
</>
);
注意点 : useStateは関数コンポーネントの一番上でしか読み込みできない
- export const の直後にしか読み込みができない
再レンダリング
再レンダリングとは
- 再レンダリング = set関数を含む処理が完了した後に、その関数コンポーネントを再評価してstateの更新を描画しなおすこと
- React18以降は、strictModeだと、開発時のみ、再レンダリングが2回走る
再レンダリングの実行条件
- ①そのコンポーネントのstateが更新された時
- ②propsを受け取るコンポーネントがpropsが更新された時
- ③子コンポーネントから見た、親コンポーネントが再レンダリングされた時
Too many re-renders
- 初心者がよく出くわすReactのError
- 以下の無限ループに陥っている状態
- 特定の条件式でset関数を実行してstateを更新する
- その更新を検知して再レンダリングが行われる
- 再レンダリングが行われたことで、条件式が再度実行される
- これらが繰り替えされる
useEffect
useEffectとは
- 複数のset関数の更新処理が競合してしまい、先行処理が打ち消されることがある
- このような問題の対策として、useEffectというフックを用いることで、処理の関心を切り分けることができる
使い方
- useEffectは関数なので()をつけて実行する
- 第1引数に関数を受け取る仕様
- 第2引数を設定していない場合は、再レンダリングの度にuseEffectが実行される
- 第2引数
- 第2引数の配列の中で指定したstateの更新があった時だけ、useEffectが実行されるという仕様
- そのため、空配列(
[]
)を設定すると、最初のマウント時のみuseEffectが実行されるようになる - set関数の第一引数を配列の要素に指定することで、そのstate更新時だけに実行する処理をuserEffectに実装することができるようになる
useEffect(() => {
// ここに処理を書く
}, [useStateの第一引数]
Udemyの教材のセクション7
内容のまとめ
- セクション5で作成したTodoアプリをReactで作成し直す
- mapを用いて、タスクたちをリストとしてレンダリングする
- useStateを用いて完了、未完了の配列の更新を行う
- component化して切り出す方法
注意点についてメモ
クラスをタグに付与する時jsx記法では、classNameとして付与する
- classだとreactのクラス構文として認識されるため以下のように記載する
<div className>hoge</div>
イベントに同期する関数でeventという引数が使える
- HTMLのイベントが発火すると、eventという引数が、イベントで設定している関数へ渡ってくる
- そのため以下のように記述することができる
const onChangeTodoText = (event) => {
setTodoText(event.target.value);
};
return (
<>
<div className="input-area">
<input
placeholder="TODOを入力"
value={todoText}
onChange={onChangeTodoText}
/>
<button>追加</button>
</div>
</>
);
イベントに指定する関数で引数も渡す場合は,アロー関数の処理のところに記載する
- jsxの記述で、イベントに同期して関数が実行されるような記述の場合に、引数も一緒に受け取りたいとする
- このような記述は、関数(引数) とイベントの直後に記載すると、関数を実行するといいう解釈をされてしまう
- そのためレンダリングの毎に関数が実行されるため適切ではない
- この場合は、新たにアロー関数を設定
- その関数の処理の中身として、イベントの関数を実行してあげる必要がある
onClick={() => イベントの関数(引数)}
❌ : エラーとなる記述方法
const onClickDelete = (index) => {
const newTodos = [...incompleteTodos];
newTodos.splice(index, 1);
setIncompleteTodos(newTodos);
};
return (
<>
<ul>
{incompleteTodos.map((todo, idnex) => (
<li key={todo}>
<div className="list-row">
<p className="todo-item">{todo}</p>
<button>完了</button>
<button onClick={onClickDelete(index)}>削除</button>
</div>
</li>
))}
</ul>
</>
);
⭕️ : エラーにならない記述方法
const onClickDelete = (index) => {
const newTodos = [...incompleteTodos];
newTodos.splice(index, 1);
setIncompleteTodos(newTodos);
};
return (
<>
<ul>
{incompleteTodos.map((todo, idnex) => (
<li key={todo}>
<div className="list-row">
<p className="todo-item">{todo}</p>
<button>完了</button>
<button onClick={() => onClickDelete(index)}>削除</button>
</div>
</li>
))}
</ul>
</>
);
Reactのset関数を更新する際のトリガーの規定について
- Reactのset関数は配列が全く新しいものになったかどうか? で判定をする
- そのため、state自体を破壊的に更新する記述だと変更を検知してくらない
- そのため、新たに変数を定義してそれをset関数に渡す記述で記載する必要がある
component化について
component化
- ここまで実装した内容を、タグの種類に応じて関数コンポーネントする
- その時、porps経由で必要な変数や関数を渡す必要がある
component化のメリット
- ①コードの見通しがよくなる
- コンポーネント名からHTML構造が読み取りやすくなる
- ②componentの再利用が可能
- componentの抽象度を上げることで、使い回すことができる範囲が増える
- この時、component化してないと使い回すことができない
styled component
- component切り出しした処理の中だけで使用しているcssのスタイルが存在する
- しかし、cssはプロジェクト全体に影響する一番外側のファイルで記述している
- スタイルが指定できるスコープを狭くすることで不要な影響が発生することを避ける思想のことをstyled componentと呼ぶ
手続き的と宣言的の違い
- プレーンなjsは手続き的な記述でDOM操作をする必要があった
- 「何を」ど「のように操作」するかの処理が、全てコードで順番に記載されている
- 操作を完了した後のHTML構造は手続きを全て追わないとわからない
- Reactでは、手続きではなく宣言的な記述でDOM操作が可能
- HTMLの構造は変更せずに、その中身をどう取得してどのように変更するかは、別の箇所に切り出されている
- 処理を追わなくても、操作完了後のDOMのデータ構造が最初から分かる