Reactを使い始めた際に、筆者が最初のうち戸惑って調べてみたことをまとめてみました。
この記事の対象の読者
Reactを使い始めるにあたって、散乱している記事のうち、とりあえず何にフォーカスして考えはじめれば良いか迷っている人。
VueやAngularなどを触ったことはあるが、Reactは初めて触る人。
JSの基礎を理解していて、Reactの詳細よりも前に、考え方などを大まかに知りたい人が対象です。
Reactを始めるにあたって
本当に基本的な部分については、Vueのような他のフレームワークと共通しています。
例えば、コンポーネントベースであること、DOM操作を隠蔽してくれるような部分です。
ただ、やはり異なるところも多くあります。
当然、アプリケーションを作成していくことで覚えられる部分も多いですが、事前に知っておいた方が良いことも結構たくさんあります。
全体的な概要を知るためには、まず [React公式のドキュメント] を読むことをおすすめします。
読んでから書き始めてなお、つまづきどころはありますし、振り返って "そういえば公式ドキュメントにも書かれていた"と思うことも結構あります。
ですが、Reactがどういうものなのかを理解するのには重要です。
コンポーネントの書き方について
Function Component と Class Component
Reactのコンポーネントの記述方法は二つあり、検索すると両方が無秩序にヒットします。
そのため、そのコードがどちらで書かれたものなのかをちゃんと理解できるようにしましょう。
二つというのは、Function Component
と Class Component
の二つです。
- 現在(執筆時点)のトレンドは
Function Component
の方です。
これは、ReactHooks
がリリースされたことで、Class Component
の冗長な記述が不要になって、シンプルに記述できるようになったから、というのが理由の一つに挙げられるようです。
もちろん Class Component
で書いていけない訳ではありません。
サポートされていますし、多くのOSSが Class Component
の記述方式で書かれています。
ただ、もし、全く新しくプロジェクトを始めるのであれば、より書き方が簡潔な Function Component
の方をおすすめします。
また、既に Class Component
の形式で書いている部分がある場合でも、部分的に Function Component
を利用できます。
その場合、単に Function Component
の形式で書けば良いだけです。
Function Componentでの開発方法
Function Componentでは、これまでのComponentベースの開発方法に加えて、React Hooks
を使った開発が推奨されています。
React Hooks
の主だったHooksには以下のようなものがあります。
このあたりは全て、オフィシャルのドキュメントから探すことができます。
また、これに加えてReactコミュニティが作成している以下のようなHooksがあります。
リンク先を少し見てみるとわかりますが、本当にたくさんのHooksがあります。
そのため、Hooksを作りたくなるような場面に遭遇したら、まず先に誰かが既に作っていないか検索してみることをおすすめします。
また、実際の開発では、さらに、自分たちでアプリケーション用のカスタムフックを作成しながら
、開発していくことになります。
Hooksの制限
Function Component
に直接書かれている必要があります
Class Component
やプレーンなJS
に書かないようにしてください
条件文やループ文の中、ネストされた関数内に書くことはできません
Hooksは、条件文やループの中、ネストされた関数の中には書かないでください
書いた場合、フックの順序が変更され、バグを引き起こすことがあります
- 上記の制限にひっかかる場合は、一般的にはコンポーネントを分割して、Hooksをコンポーネントの中に条件やループなしで書いた上で、コンポーネントを条件にやループによって呼び出すように変更します
Hooksの命名
- 自身でカスタムフックを作る場合は、接頭辞に
use
をつけるようにしましょう。- ほとんどのフックには、コミュニティのライブラリまで含めて、
useSome
のように命名されています。 - 同様の命名を行うことで、可読性を維持でき、誤解を招かずにすみます。
- ほとんどのフックには、コミュニティのライブラリまで含めて、
Reactにおける状態管理
Reactには状態管理の方法がいくつか提供されています。
そのうち、Hooksで提供されているのは
- useState
- useReducer
を使った状態管理です。
StateとReducerの使い分けは、Stateは単純な状態管理を、Reducerはより複雑な状態管理を行うという感じで使います。
あるいは、Hooksの登場前からよく使われている [Redux] を使う選択肢もあります。
ReduxはHooksのState,Reducerを使った状態管理よりも、さらに複雑な状態管理を行いたい場合に使用します。
具体的には、"状態を他のコンポーネントとも共有したいようなケース"が増えてきた場合は、Reduxを使う方が開発が楽になります。
これはState,Reducerを使った状態管理がコンポーネント内(ローカル)に閉じているのに対し、Reduxの状態管理はグローバルで行うため、他のコンポーネントでも状態を共有できるからです。
つまり、Reduxの原則の一つの Single source of truth / 信頼できる唯一の情報源
を活用できるからです。
また、今では Redux
と Hooks
を組みあせて使うこともできます。
その場合は、Reduxのconnect関数を使うための面倒な手順を簡素化できるため、新しくReduxを使う際には、Hooksと組み合わせて使うと良いと思います。
参考: Using Hooks in a React Redux App
参考: Reactのステート管理方法まとめ
他のキャッシュ層との兼ね合い
GraphQL
などを使っている場合は、AppoloClient
などを使っていることもあるでしょう。
その場合は、Clientがキャッシュを持っているので、このキャッシュを 単純なStore代わり
にすることもあります。
APIから、情報を受け取り、それをレンダリングし、ある程度扱いやすいUIを提供するのが主目的のアプリケーションなら、Reduxも使わず、State,Reducerも最低限で済ます構成も充分に考えられます。
構造も単純になり、開発も早いです。
状態管理のまとめ
状態管理は、アプリケーションの規模や構成によって、適切なものを選ぶのが良さそうです。
- 小さいアプリケーション、あるいは、構成がシンプルなアプリケーションではState,Reducerを使った最低限の状態管理。
- 中規模以上のアプリケーション、一画面上で様々な表現を一度に行うようなアプリケーションではReduxを使った状態管理。
という感じになるかと思います。
アプリケーション規模が小さいからといって、必ずしもHooksが推奨されるわけではなく、他のコンポーネントとどの程度状態を共有する必要があるか、が指標になるという点については注意が必要かと思います。
幾つかの原則
Reactのコンセプト
Declarative (宣言的な View)
宣言的に書くというのは、やりたいことを手続き的に書くのではなく、何をしたいのか
を書く、ということです。
ReactはDOMを操作する部分を隠蔽してくれるので、プログラマは 何をしたいのか
の部分に集中して書くことができます。
本質的には、できるだけ宣言的に書いたほうが良い、というのはReactに限ったことではありません。
通常のプログラミングでも、できるだけ宣言的に書いた方が良いです。
Component-Based (コンポーネントベース)
Reactでは(当然のことながら)コンポーネントを中心に開発が行われます。
設計も画面デザインを基に、どのようにコンポーネントを分割するか/あるいは共有するか、を最初に考えるのが基本です。
コンポーネントを共有する場合には、共有するコンポーネントがCSSに直接依存していると使いにくい場合も多いです。
また、Hooksが出てきたことによって、Hooksをどのように活用すべきか、という点もちゃんと考えた方が良いと個人的には思います。
Learn Once, Run Anywhere (一度学習すれば、どこでも使える)
ReactはReact Nativeなどネイティブアプリ向けでも同じようなニュアンスで開発を行うことができます。(完全に同じではありませんが)
ネイティブアプリ開発者が社内にいない/少ない場合には、Webアプリ開発者のリソースで開発できる、という点でメリットがあります。
Default関数 / Renderメソッド
Function Component
では、 Default関数
、Class Component
では Renderメソッド
にあたります。
この二つの関数/メソッドは出来るだけ副作用がないように作成します。
完全にはできませんが、できるだけ副作用がないように作ることで、コンポーネントの構成をシンプルに保つことができます。
1コンポーネント1機能(単一責任の原則)
Reactに限らず、プログラミングでは頻出の原則です。
一つのコンポーネント、あるいは一つの関数、メソッドは、一つの機能を実現するように作る、という原則です。
この原則を守ることで、コンポーネントや関数がシンプルに保たれます。
一つの関数内の行数が少なくなりますし、全体的に可読性を維持できます。テストもしやすく、変更による影響の見通しもよくなります。
Reduxの原則
- Single source of truth(信頼できる唯一の情報源)
- State in read-only(stateは読み取り専用にする)
- Changes are made with pure functions(変更はすべて純粋関数で行われる)
ReactでのAPIからのデータのフェッチについて
多くのケースでは、ReactとAxiosなどのAPIClientを用いて、バックエンドのAPIサーバからデータを取得してきて、それを画面に表示させる部分があると思います。
データのフェッチをどこで行うか、については基本的には以下のように考えると良いと思います。
- データを使うコンポーネントの親になるコンポーネントでフェッチする
- 自分でデータを使い、他にデータを使うコンポーネントがないなら自身でフェッチする
- データのロード中を示すぐるぐるが自分のコンポーネントより上になるなら、ぐるぐるを表示しているコンポーネントでフェッチする
これには、データをフェッチする回数を減らす意図と、データのローディング表示をシンプルに処理する意図があります。
場合によっては、このケースから外れることもあるかもしれませんが、基本的にはこの考え方で組んでいって問題ないと思います。
参考: How to fetch data in React
Componentとスタイルの分離
Componentの再利用性を上げる方法として、Componentとスタイルを分離する方法があります。
Reactの考え方は、そもそもComponent Basedなので、できるだけ適切にComponentを分離するのはとても大切です。
ただ、Componentを綺麗に分離していても、Component自身がデザインに依存していると再利用性は極端に下がってしまいます。
そのため、再利用性を上げるためにComponentとスタイルを分離します。
基本的には、Componentをラッピングしてスタイルを与えるだけのComponentを作成して実現します。
これは一つづつ作成するというよりは、複数のComponentをまとめている親のコンポーネントから与える形になることが多いです。
重要な点は、Component自身がスタイルを知らなくて良いようにしておくことです。
もちろん全てのComponentをスタイルと分離する必要はありません。
大きめのComponentはそもそもデザインに依存していることも多いです。また、明らかに再利用できる必要がないことも多いです。
逆に小さめのComponentはデザインに依存していると再利用できないので、できるだけスタイルを分離しておくようにします。
学習時の参考に
React で作られた OSS
書籍
-
React開発 現場の教科書
- 実践的な書き方を伝える本ではありません。考え方を伝える本です。コードも記載されていますが、あくまで考え方を理解するためのものとして読むものだと考えると良いと思います。
-
React Hooks
- React Hooksについて、ステップバイステップで丁寧に説明している書籍です(英語です)。Hooksの使い方を初心者向けに解説しています。useStateを簡易的に自身で再実装したり、Hooksを使っている最中に直面しがちな問題についての一般的な解決策などを学ぶことができます。
- 一つ一つのステップは非常にシンプルに記述されており、徐々により具体的な活用方法を示すように作られているので、とてもわかりやすいです。