React入門 関数コンポーネントとは

今日はReactの関数コンポーネントについて解説いたします。初めてReactに触れる方でも読んで頂けるように、最低限のコードを引用しつつも概念的な話をメインにしております。

Reactはコンポーネントベース

Reactの最大の特徴は、WebサイトあるいはWebアプリをコンポート(部品)に分けて作成できる点です。例えば下記の図のように、各コンポート1.2.3をそれぞれ別のJSファイルで作成した上、中央のファイル(App.js)でそれらを読み込んでサイトを構築できます。





具体的なReactのコードは下記の通りです。ここではProfileという名称のコンポーネントを1行目でインポートし、それを2-4行目で3回表示させています(上記の中央部分の2に相当)。Profileというコンポーネントの名称は任意で、コンポーネント名に.jsを付けたProfile.jsというファイルからのインポートになります。一度作った部品を、何度も使えることがわかって頂けるかと思います。



import Profile from ‘./Profile’
< Profile />
< Profile />
< Profile />

また、Webサイトがより複雑になったとしても、Reactでは各コンポーネントを別々にデザインすることができ、完成後に組み合わせるだけなので、全体の構築もメンテナンスも容易になります(分業も容易)。下記では5つのコンポートを組み合わせています。3回使われているProfileのメンテナンスも、単一のコンポーネントファイル、Profile.jsの変更だけで済みます。





Reactの関数コンポーネント

コンポーネントの機能を実装するため、Reactには、クラスコンポーネントと関数コンポーネントが用意されています。2013年にリリースされたReactですが、2019年までは関数コンポーネントの機能が限定的であったため、ちょっとしたWebアプリを作るにもクラスコンポーネントが不可欠でした。Reactの公式ドキュメントでもクラスコンポーネントの解説から始まります。

ところがこのクラス概念、JavaやC#などクラスを多用する言語の経験者にとっては馴染みがあるも、純粋なフロントエンドエンジニアにとっては難解な概念です。下記イメージは、Reactの公式ドキュメントの解説、Hello Worldから始まって5つ目の章で初めて紹介されるクラスコンポーネントのコードですが、冒頭のコンストラクターとthisで多くのフロントエンドエンジニアが躓いてきたと思われます。

多くの内外のReactの入門書やプログラミングスクールも、2015年頃(Reactが流行りだした頃)に大部分の内容を作り、2019年のHooksの登場に合わせて部分的に修正を加えたものが多いので、今でも難解なクラスコンポーネントが先に登場し、わかりやすい関数コンポーネントが従たる位置付けで後に解説されているものが多いように思います(注意が必要)。





さて2019年、Reactは関数コンポーネントの新たな機能としてHooks(後述)をリリースしたことで、関数コンポーネントでもクラスコンポーネントと同じ機能を実装できるようになりました。

関数コンポーネントは、文字通り関数のようにコンポートを作ることをできます。引数(Reactではpropsと呼ばれる(後述))を受け、アウトプット(戻り値)としてHTML(Reactの場合はJSXと呼ばれる)を返す、非常にわかりやすい構造をしています。

JSXは、HTMLの内側にJavaScriptが組み込まれたものです。HTMLに組み込まれたJavaScriptは、波括弧{}の内側に入るだけなので、HTMLとJavaScriptが扱えるフロントエンドエンジニアにとっては、新たに何かを学ぶ必要がないということなります。





下記関数コンポーネントのコードは、React公式ドキュメントからの引用です。先ほどご紹介したクラスコンポーネントとやっていることは違うのですが、最低限の機能しかないという点では一緒です。

コンポーネントの名称はExampleで、Exampleという名称のJavaScriptで書かれた関数があります。ここでは引数はなく、関数内のusetState(Hooksの一種(後述))でcountという変数を宣言しています。returnから先は戻り値で、関数コンポーネントでは下記の通り、HTML(JSX)を丸ごと返しております。

2018年以前の関数コンポーネントでは、このuseStateがなかったので、JSX内部で変数を保持することができませんでした。





Reactにおけるpropsとは

先ほど関数コンポーネントの引数として紹介したprops(propertiesの略)ですが、コンポーネントを跨いで値が引き渡される点が特徴です。また、上位コンポーネントでは変数として宣言されますが、下位コンポーネントの中ではpropsを通じて引数として受けるので定数になる(Read Onlyになる)点も重要です。

具体的な例は、公式ドキュメントから引用します。下記では、1つのファイルでは書かれていますが、2つの独立した関数コンポーネントがあります。順番が逆になっているのでわかりにくいのですが、Appが上位関数コンポーネントで、Welcomeが下位関数コンポーネントです。上位のAppコンポーネントからpropsを通じて下位のWelcomeコンポーネントに引数を渡しつつ、Welcomeコンポーネントを3回呼び出しています。

下位コンポーネントでは、上位コンポーネントのAppから引数として受けたpropsに、.nameを使ってそれぞれの値、”Sara”、”Cahal”、”Edite”を取得、表示させています。同じWelcomeコンポーネントでも、propsで受け渡す内容によって表示が変わります。





こちら実行すると、

Hello, Sara

Hello, Cahal

Hello, Edite

となります。引数として外部から渡されていますので、先ほども申し上げたように、Welcomeコンポーネントの内部ではこの値を定数のように扱われます。





関数コンポーネントのHooksとは

Hooksは2019年のReact 16.8から新たに導入され、16.7以前はクラスコンポーネントにしかなかった、state、ライフサイクルなどの機能を関数コンポーネントでも使えるようにしたものです。特徴としては、次の通りです。

  1. ただの関数である
  2. 実行が容易である
  3. クラスで同じことを実装するより軽い
  4. (クラスコンポーネントより)テストが容易である
  5. カスタムHooksが作れる

代表的なHooksは、(1)JSX内の変数を宣言するuseState、(2)サイトのライフサイクル毎の動き(初回読み込み時など)を規定するuseEffect、(3)JSX内を参照できるuseRefの3つで、この3つだけでも複雑なWebアプリの作成が可能です。例えば私のこちらの新型コロナのWebアプリでは、useStateとuseEffectの2つを使って動かしています。

最後に代表的なHooksであるStateについて解説したいと思います。

Stateとは

StateはReactのための変数で、特定のコンポーネントの内部で宣言され同コンポーネントのJSXの内部で変数として機能します。反対に捉えると、Reactのコンポーネントの外で宣言される変数は、JavaScriptの通常の変数としてもちろん使用可能ですが、コンポーネントのJSXの内部では変数として動けません。コンポーネント外の変数とは、前述propsで受ける変数の他、コンポーネントが記述されたjsファイルでも関数の外で宣言された変数が該当します。

変数として動けないということは、例えば、クリックする都度、1をその変数に足してその変数を表示させるコードを書いても、JSX内では表示が変わらないということです。

一つのWebサイト又はWebアプリに多数のコンポーネントがある場合は、それぞれがStateを持つことができ、かつ、互いに独立です。Stateは各コンポーネントの内側だけで機能し、複数のコンポーネント間で共有できません。

下記がStateのイメージ図です。コンポーネント内でuseStateを用いて宣言されたstate変数Aとstate変数Bはそれぞれのコンポーネント内では動きますが、互いに共有できません(独立)。変数Cは上位のコンポーネントからpropsを使ってコンポーネントAとコンポーネントCの間で共有されていますが、このCはコンポーネントの内側では変数として機能しません。

変数CをコンポーネントAとBでも動かしたい場合は、コンポーネントAとコンポーネントBを包含する上位コンポーネントCの機能として実装すればいいということになります。階層構造含めてなかなか概念図では理解しにくいのですが、実際にコードを書くと実感できると思います。





今日も最後まで読んで頂きありがとうございました。