Reactに入門する!
参考書籍
『モダンJavaScriptの基本から始める React実践の教科書』
▼React公式サイト
Reactプロジェクトの始め方
npmのcreate-react-app [プロジェクト名]
で必要なファイルやいい感じのフォルダ構成を生成してくれる。これで始めるのが一般的みたい。
あとは[プロジェクト名]
のディレクトリに移動してnpm start
で実行できる。
Reactの基本的な考え方
JSファイル上ではHTML要素(DOM)を返す関数をコンポーネントとして実装していき、それをHTMLにレンダリングする。
コンポーネント単位で実装していくことで再利用性や保守性を高めることができる。
React18におけるレンダリングの注意点
学び始めていきなりコンソールに警告。
初学者泣かせ
ついこないだ(2022/03/29)リリースされたReact18でレンダリングのAPIが変更されたことがことが理由みたい。当然書籍にはない情報。
フロントエンドは移り変わりが早いってよく聞くけど、本当にそうじゃん…。
スタイルの当て方について
HTMLよろしくタグにstyle
で当てることができる。
<h1 style={{color:"red"}}>Hello, world!</h1>
style={{}}
となっているのは、style={}
(←この{}
は「この中にJS書くよ~」のやつ)の中にJSのオブジェクト{}
を代入しているから。
もちろん別の変数で定義して代入することも可能。(というかそっちのほうがメインだろう)
まだ出てきていないがよくあるWeb制作のようにCSSファイルを読み込んだり、CSS-in-JS(見たことある…!)という書き方もあるらしい。
propsの使い方
コンポーネントには関数の引数のように値を渡すことができ、これをpropsという。
「同じボタンなんだけど色を変えたい…」というような場合に有効で、これを使うことで似たコンポーネントの再利用ができる。
Web制作の文脈でいえば、SCSSのmixinのような感じで使える。
propsのchildren
コンポーネントを呼び出す際に、HTMLのように要素内にテキストなどを書いて渡すこともできる。
<SomeComponent>Hello</SomeComponent>
コンポーネント内ではこのHello
はprops.children
として扱えて、テキストだけでなく大きなDOMをまるごと渡すこともできる。
…なにやらコンポーネントをコンポーネントに渡す…みたいな使い方になりそうな予感…。
Stateについて
Reactではコンポーネントの状態をState
として管理する。イベントがあったときなどにStateを更新することで、動的なアプリケーションとして機能させていく。
Stateに変更があったタイミングでそのコンポーネントを頭から処理し直し、該当箇所が再レンダリングされるという仕組み。
基本的な使い方はuseState()
という関数。
const [num, setNum] = useState(0);
これで初期値としてnum = 0
のStateが定義される。
そして例えば
const onClickButton = () => {
setNum(num + 1);
};
とすることで、ボタンクリック時にnum
をインクリメントすることができる。
※ちなみに上記のsetNum(num + 1)
は、動作はするが厳密に正しい書き方ではない。ここにはアロー関数など、ちゃんと関数を書くべし。
CSSの当て方
一般的なもので5~6種類はあるみたい。どれがデファクトスタンダード…とかもあまり無いらしく、プロジェクトの特性によって選定していくもの、という感覚でいる必要あり。
Inline Styles(インラインスタイル)
コンポーネントのタグに直接スタイルを指定する、HTMLのインラインに書くようなタイプの指定方法。
<p style={{color : "pink", width : "100%"}}>Hello</p>
HTMLでも構造とスタイルの分離の観点からこのように書くことはほとんどないように、Reactの開発でもほとんど使わないと考えて良さそう。
CSS Modules
よくあるWeb制作のように、CSS(SCSS)ファイルを別で用意して適用する方法。
JSX側でインポートして使う。
import classes from "./CssModules.module.scss";
export const CssModules = () => {
return (
<p className={classes.title}>CSS Modules です</p>
);
};
Web制作をしてきた人や、デザイナーさんと協業する場合にはよさそう。
また、コンポーネントごとに名前空間が閉じられるそうなので名前の競合も避けられてよき。
Styled JSX
Next.jsに標準で組み込まれているライブラリ。 CSS-in-JS (見たことあるぞ…!)の一種。
JSX内にスタイルを記述する方法。
return (
<>
<div></div>
<style jsx>{`
/* ここにCSS */
`}</style>
</>
このままでは SCSS記法が使えない ことに注意。別途ライブラリが必要。
JSXに埋め込んで書く、ということは他のコンポーネントに影響を与えない。その点でよさそう。
styled components
これもCSS-in-JSの一種。 スタイルをあてたコンポーネントを定義する のが特徴。
import styled from "styled-components";
export const StyledComponents = () => {
return (
<SContainer></SContainer>
);
};
const SContainer = styled.div`
padding: 1rem;
`;
な…なるほど!構造周りはスッキリさせつつ見やすくして、スタイルのスコープもあるって感じですかね。
SCSSが使えるのも個人的には嬉しいポイント。
Emotion
これまで見てきた記法に似た、幅広い使い方が用意されている方法。
インラインのように書いたり、styled componentsのように書いたりできるので、開発チーム内でベストプラクティスが見つかっていないときなどの選択肢になるよう。
→保守性が下がるのでは?
Tailwind CSS
TailwindはReactだけじゃなくWeb制作の文脈でも見聞きするレベルで人気な気がする。
HTMLのクラスに独自のクラス名を書いていくだけでスタイルがあてられるという、「ユーティリティファースト」な思想。
これまで「HTMLが見づらくなるな~」と思って敬遠してきたけど、触ってみるとこれはたしかに実装が早くなるかもしれない。(ゴクリ)
もしチームが「Tailwind分かり手」のみで構成されていたら、どれだけ意思疎通がスムーズになるのだろうか…!
レンダリングの最適化
コンポーネントの再レンダリングをうまく制御しないと、不要なレンダリングによりパフォーマンスの低下を招く場合がある。
コンポーネントが再レンダリングされるパターンは以下の3つ。
- Stateが更新されたとき
- Propsが変更されたとき
- 再レンダリングされたコンポーネント配下のすべてのコンポーネント
特に重要なのが3で、不必要な再レンダリングを招きがちになるので注意が必要。
メモ化
メモ化 とは、前回の処理結果を保持しておくことで、不要な再計算を省くことができる技術。
Reactに標準装備となっていて、コンポーネントをまるごと以下の書式で囲むことで、Propsに変更がない限り再レンダリングされないようにしてくれる。
コンポーネントのメモ化(memo())
const Component = memo(() => {});
関数のメモ化(useCallback())
関数をpropsで渡すとき、propsが変更されたわけではないのにコンポーネントが再レンダリングされてしまうのは、関数が再生成されているから。
これを回避するために 関数のメモ化 をする必要がある。関数のメモ化にはReactのuseCallback
を使う。
書式はuseEffect
と同様、第1引数に関数、第2引数に依存配列。
const onClickButton = useCallback(() => {
alert();
}, [] );
変数のメモ化(useMemo())
使用頻度は高くないが、useMemo()
を使うことで変数もメモ化することができる。
const sum = useMemo(() => {
return 1 + 3;
}, []);
変数設定のロジックが複雑だったり、膨大なループがされる場合などにパフォーマンスを上げる効果が期待できる。
グローバルなState管理
コンポーネントにpropsとして値を渡せば、深い階層でも上位コンポーネントのStateを参照できる。
しかし、中間コンポーネントでは必要のないpropsを受け取っていることになり、冗長で再利用性が下がり、propsを参照しているがために再レンダリングされてしまう問題もある。
この問題を解決するために、グローバルなState管理の方法が用意されている。
ReactのContextを使う方法
Reactに用意されているContextという機能を使うことでStateのグローバル化が可能。
今回なんとなくしか理解できなかったので、今後がっつり復習が必要そう…。
Reduxを使う方法
Redux 。これなんか方々で見たことあるぞ…!ここで登場するんか!
すべてのStateをStoreという場所に入れておき、定義されたActionにしたがって値を変更してコンポーネントに反映する仕組み。
フローが一方通行になるのがメリット。
これは直感的に理解しやすいかも。
Recoil
Meta社が進めている状態管理のライブラリ。ReactもMeta社が作ったので、親和性が高いであろうことは予想できる。
今から自分が技術選定するならこれかも。
Apollo Client
GlaphQLを使っているなら選択肢に入ってくるらしい。
TypeScript
出ました TypeScript !
JavaScriptに「型」の概念を持ち込むことができるスーバーセット。
今のフロントエンドといえばコレ。みたいなイメージがあり、少しどんなものか覗いたことはあるものの、今回のようにちゃんと説明を通読したのははじめて。
書籍の説明もわかりやすくてスラスラと読めてしまった。今後実装していく際には慣れるまでは基本の型定義に立ち戻りながら使っていこう。
TypeScriptはマイクロソフトが開発していることもあって、ジェネリック型などの考え方がC#と非常に似ていてとっつきやすかった。
学生時代のCやJavaから始まり、新卒時代のC#(.NET)の記憶も相まってか、「型があると開発しやすいよね」という考え方にすごく賛同する。
(Pythonも書き方がわかりやすくていいんだけどねっ)
カスタムフック
書籍を通読した感じ、カスタムフックは、コンポーネントからロジックを分離するために用いる自作の関数というイメージ。
Reactで用意されているHooksと同様に「use〇〇」というネーミングにすることが推奨されているよう。
本来、データの表示のみを扱うべきコンポーネントにロジックをベタ書きしてしまうと、再利用性や可読性の低下を招くため、カスタムフックが必要になる。
MVCのようなモデルにおけるModel(ロジック)とView(表示)の関係に似たものを感じた。
逆に今までロジックを分離しないでどうしていたんだろうと思ったが、Stateを子孫コンポーネントにどんどん渡していくことで成り立っていたため、状態の管理が複雑になったり、不要なロジックやプロパティが中間コンポーネントに混ざってしまう問題が起きていたみたい。