UdemyでReact学習を進めていく中で得た基礎知識や気になったことを調査し、キーワードをまとめました。
講座について
オススメUdemy講座
神講座と名高いReact完全入門ガイド。
コーディングに留まらず、内部構造や周辺知識を分かりやすく図で説明してくれるので、納得感を持って学習を進めていけます。
これからReactを学びたいと思っている方には全員にオススメできます。まさに神講座。
DOMと仮想DOM
DOM(Document Object Model)とは、JavaScript(※以下JS)によってHTMLを操作する仕組みのこと。
仮想DOMとは、実際のDOMと同じデータ構造をJSオブジェクトとして表現したもの。
Reactでは仮想DOMを操作し、差分のみを実際のDOMに反映させることでパフォーマンスの向上を実現している。
JSX
JSX(Javascript Syntax Extension)とは、ReactによるJSの拡張機能。
一見HTMLタグのような記述を「babel」によって関数に置き換えられ、Javascriptオブジェクト(React要素)に変換される。
<h1 className="sample">
Hello World
</h1>
↓
React.createElement(
'h1',
{className: 'sample'},
Hello World
)
↓
{
type: 'h1',
props: {
className: 'sample',
childlen: 'Hello World'
}
}
babel
新しいバージョンでの記述方法で書かれたJavaScript(※以下JS)を古いバージョンでも動かすために互換してくれるツール。
ユーザーの使用しているブラウザによって対応しているバージョンが異なる問題を解決できる。
コンポーネント
画面の各構成要素を定義したもの。関数によって定義されるコンポーネントを「関数コンポーネント」といい、後述するpropsを受け取りJSXを返す。
名前の先頭は必ず大文字である必要がある。
(babelが読み込むのは大文字のため)
// 定義
function Welcome() {
return <h1>Hello</h1>;
}
// コンポーネントの呼び出し
<Welcome />
メリット
・再利用性の向上(コードが使いまわせる)
・可読性の向上(コードが整理される)
・疎結合になる(バグを減らせる)
例:コンポーネントごとにテストできる
コンポーネントにおけるkey
同一要素を一意に識別する仕組み。
リストやコンポーネントに使われる。
<Component key="A" />
<Component key="B" />
メリット
子要素を識別可能になり、変更のあった要素のみを差分更新(commit)できるため、処理を効率化できる。
props
親コンポーネントから子コンポーネントに渡すことができる読み取り専用のオブジェクトプロパティ。
パラメーターを渡すことにより、子コンポーネントの挙動やスタイルを変えて使いまわせる。
import Child from "./components/Child";
const Example = () => {
return (
<Child text="Good Morning" /> //Good Morning
);
};
const Child = (props.text) => {
return (
<h3>{props.text}</h3>
);
};
// デフォルトパラメーターの設定や分割代入もできる
/* const Child = ({ text="Hello" }) => {
return (
<h3>{text}</h3>
);
}; */
export default Child;
特別なプロパティ(props.children)
子コンポーネントに別のコンポーネントを渡すことができる。
props.childrenを使うケース
import Profile from "./components/Profile";
import Container from "./components/Container";
const Example = () => {
return (
<div>
// 通常の呼び出し方は <Container />
// ContainerにProfileコンポーネントを渡して呼び出す
<Container title="Childrenとは?">
<Profile />
<Profile />
</Container>
</div>
);
};
const Profile = ({ name, age, country }) => {
return (
<div className="profile">
<h3>Name: {name}</h3>
<p>Age: {age} </p>
<p>From: {country}</p>
</div>
);
};
export default Profile;
const Container = ({ title, children }) => {
return (
<div className="container">
<h3>{title}</h3>
// props.childrenとして渡ってきたProfileコンポーネントを呼び出している
<p>{children}</p>
</div>
);
};
export default Container;
エクスポートの使い分け
基本的には1ファイルにつき1コンポーネント。
そのためデフォルトエクスポートを使用するケースが多いが、
複数のコンポーネントを出力する際には名前付きエクスポートを使用する。
// デフォルトエクスポート
export default Component;
// 名前付きエクスポート
export { Component };
React.Fragmentについて
タグを生成せずに複数のルート要素をレンダリングできる仕組み。
jsxでは、一つのルート要素で束ねられている必要がある。
エラーが発生するコード
<div id="root" className="component">
<h3>Hello Component</h3>
</div>
<h3 id="root">Hello Fragment</h3>
エラー回避のためにdivで囲ったコード
<div id="root">
<div className="component">
<h3>Hello Component</h3>
</div>
<h3>Hello Fragment</h3>
</div>
しかし、上記のコードではエラーを避けるために不要なdivタグが生成されてしまう。そこで
<React.Fragment>
<div className="component">
<h3>Hello Component</h3>
</div>
<h3>Hello Fragment</h3>
</React.Fragment>
のようにするとタグを生成せずに複数のルート要素をレンダリングできる。
イベント処理
開発でよく使われるイベントタイプ
一覧形式でわかりやすくまとめてくださった記事があるので参照。
イベント一覧
入力された値を取得する方法
<input type="text" onChange={(e) => console.log(e.target.value)}
ステート(状態管理)
コンポーネント単位で変更した値を保持、管理しておく仕組み。
グローバルステート
アプリ全体で共有されるステート。
useContext
アプリケーション全体でグローバルな値を保持する仕組み。
孫の孫の孫コンポーネントまでpropsを渡すなど、バケツリレーをせずに実装できる。
Redux
グローバルステートを管理するライブラリ。
個人的にはパフォーマンスや可読性などuseContextと比較して優れていると感じるのでこちらを推奨。
ローカルステート
特定のコンポーネント内でのみ使用されるステート。
usestate
配列の0番目に参照用の値
配列の1番目に更新用の関数が渡せる。
更新は非同期に行われ、値が変わるたびに関数コンポーネントを再実行してくれる。(再レンダリング)
注意!! コンポーネントのトップレベルで呼ばなければエラーになる
import { useState } = from "React"
const Example = () => {
let [val, setVal] = useState();
if (true) {
// エラー
//let [val, setVal] = useState();
}
return (
<>
<input type="text" onChange={(e) => {
setVal(e.target.value)
}
}/> = {val}
</>
);
};
また、オブジェクトを更新する場合はstateにセットしたものと別オブジェクトである必要がある。
import { useState } from 'react';
const Example = () => {
const orderObj = { item: 'apple', count: 10 };
const [order, setOrder] = useState(orderObj);
const changeItem = (e) => {
setOrder(order => ({ ...order, item: e.target.value }));
};
return (
<div>
<h3>Item:{order.item}</h3>
<h3>Count:{order.count}</h3>
<input type="text" value={order.item} onChange={changeItem} />
</div>
);
};
useRef
再レンダリングを発生させずに値を保持する方法。
stateとの違い
・再レンダリングされてもデータが保存される
・値を変更しても再レンダリングがトリガーされない
・refオブジェクトをJSXのref属性に渡すとそのDOMにアクセスできるようになる
import { useState, useRef } from "react";
const Case1 = () => {
const [value, setValue] = useState("");
const inputRef = useRef();
return (
<div>
<h3>ユースケース1</h3>
<input type="text" ref={inputRef} value={value} onChange={(e) => setValue(e.target.value)} />
<button onClick={() => {inputRef.current.focus()}}>
インプット要素をフォーカスする
</button>
</div>
);
};
useReducer
useStateの書き換えに使用。関数宣言時に更新処理を自分で定義できる。
useStateの場合
状態の更新の仕方は利用側に託す。
import { useState } from "react";
const Example = () => {
const [state, setState] = useState(0);
// 処理をいちいち定義しなければならない
const countUp = () => {
setState((prev) => ++prev);
};
const countDown = () => {
setState((prev) => --prev);
};
useReducerの場合
状態の更新の仕方も状態側で担当する。
import { useReducer } from "react";
const Example = () => {
const [rstate, dispatch] = useReducer((prev, { type }) => {
switch (type) {
case "+":
return prev + 1;
case "-":
return prev - 1;
default:
throw new Error('不明なactionです。')
}
}, 0);
// 呼び出し方を変えるだけで違う処理を実行できる
const rcountUp = () => {
dispatch({ type: "+" });
};
const rcountDown = () => {
dispatch({ type: "-" });
};
useEffect
コンポーネント読み込み時の一度だけ実行する処理を記述できる仕組み。(再レンダリングの影響を受けない)
import { useEffect, useState } from "react";
const Example = () => {
const [time, setTime] = useState(0);
useEffect(() => {
window.setInterval(() => {
setTime((prev) => prev + 1);
}, 1000);
}, []);
return (
<h3>
<time>{time}</time>
<span>秒経過</span>
</h3>
);
};
第二引数の配列を「依存配列」といい、値を指定するとその値に依存してuseEffect内の処理を実行するようになる。
※省略してもエラーにはならないが、useEffectの挙動ではなくなるので、依存する値が無ければ空配列を渡す。
また、コンポーネント消滅時のクリーンアップ処理にも活用される。
useEffect(() => {
let intervalId = null;
intervalId = window.setInterval(() => {
console.log('interval called');
setTime(prev => prev + 1);
}, 1000);
// クリーンアップ
return () => {
window.clearInterval(intervalId)
}
}, [])