no-image

とにかくReact Hooks入門ハンズオン

最近、世間を賑わせているReact Hooksですが、とりあえず細かいことは置いといて手を動かして試してみます。

環境構築

完成品はこちら

React Hooksはまだ仕様策定中で、既存のプロジェクトに入れたくないので0から構築します。

といっても、create-react-appで。
プロジェクト名は「TrialReactHooks」とでもします。

$ mkdir TrialReactHooks
$ cd TrialReactHooks

create-react-appをインストール。$ npx create-react-app trial-react-hooks$ cd trial-react-hooks

v16.7.0-alphaのReactを入れます。$ yarn add -D react@16.7.0-alpha.0 react-dom@16.7.0-alpha.0

linterもすでに用意されているのでこれも入れてしまいましょう。$ yarn add -D eslint-plugin-react-hooks@next

eslintrc.jsを作ります。

とりあえずはこれで環境が整いました。$ yarn startで立ち上がります。

これからReact Hooksを触っていきます。

useStateを使う

公式: Using the State Hook React

最もシンプルなものです。
これまではstateを扱うときは、(とりあえずは)Classを使ってコンポーネントを作る必要がありましたが、hooksを使うと関数コンポーネントで以下のように簡潔に書くことができます。

以下は本家のサイトのものとほぼ同じものです。

このコンポーネントをApp.jsxに読み込みます。

これで完了です。
数字がインクリメントするコンポーネントが完成しました。

とりあえずブラウザで試してみると直感の通りの動きをするのがわかります。

7行目の以下の部分。
ここで、useState()関数を使用し、その2つの返り値を分割代入しています。

この関数は、現在のstateとそのstateを更新する関数を返します。
括弧の中身はそのstateの初期値になります。

例えばトグルするbooleanの例。
さっきのを書き換えてみます。

とても簡単にstateを利用することができました。
ドキュメントを読む限り、さきほどの例と同様にuseStateの2つの返り値は「hoge」と「setHoge」のように名付けるのが良さそうです。

ちなみに、最初の方の数字をインクリメントするものを従来のclassを使った書き方をすると、以下のようになります。

だいぶ厳つさが増しますね。

Class型のコンポーネントはstateを管理したり、Reduxと接続したり、lifecycleメソッドを利用するときに必須でした。

これまでもできるだけSFCで書けるようにするために高階関数ならぬ高階コンポーネント(HoC)を使ったりして再利用性を高める方策を取っていました。

ですが、このhooksが導入されたことによりわざわざ外部モジュールに頼らずとも再利用性の高いコンポーネントを作ることができるようになりました。

HoCを実現するための便利モジュール郡の代表にrecomposeがありましたが、Hooksの発表により役目を終えたということで開発が終了されました。

【参考】acdlite/recompose: A React utility belt for function components and higher-order components.

useEffectを使う

公式: Using the Effect Hook React

次にuseEffectを使ってみます。
これはデータのfetchやDOM操作など、レンダリングの前後に行う副作用の処理を書くときに使うものです。

従来、class内で使われていたcomponentDidMount, componentDidUpdate, componentWillUnmountが一つのAPIであるuseEffectにまとめられたようです。

デフォルトではEffectはレンダリング後に実行されますが、return句を書くとunmount時に実行する関数を書けます。

以下のようにconsole.logを埋め込むことで確認できます。

これの何が嬉しいのかというと、これまでcomponentDidMountでなにかのAPIのsubscribeを開始し、componentDidUpdateでunsubscribeするような処理に使われていました。

これらはほぼ同じような処理にもかかわらず、2つに分けて記述する必要がありました。

これをuseEffectを使うことで、密接した場所に書くことができ、可読性の高いコードを書けるようになります。

たしかに。これはclassよりも強力ですね・・。
React開発チームは完全にclassなしでも記述できるように向かっているようです。

パフォーマンスを気にするなら

参考: https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects

実はこのuseEffect関数は第2引数を取ることができ、ここにstateを記述すると、再レンダリング時にそのstateが更新されていれば、この関数内の処理が走るように最適化できます。

これは従来のshouldComponentUpdateにも似てますね。

Custom Hooksを知る

公式: Building Your Own Hooks – React

あと1つ触ってみます。
公式のところには何かいろいろ書いてありますが、とりあえずはこれらのhooksはjsxを返すもの関数(コンポーネント)以外にも使えるということです。

以下のコードのように、返り値がJSXではなく、string型の関数を定義していますが、この中でもuseEffectを使用することができます。

この関数はいつもと同じように以下のように使うことができます。

こうすれば、10より小さい間は「Loading…」と出て、それより大きくなると「Finish」と表示されます。
これは一件普通の関数定義と変わらないですが、console.logを覗くと、描画の前後に出力があることがわかります。

このようにすることで、コンポーネントだけでなくステートフルな「ロジック」の部分も再利用することができるようになります。

これまでもHoCを使って「UI部分」と「ロジック部分」のコンポーネントを組み合わせるAtomicDesignなどの開発の仕方がありましたが、これまたHoCを使わずに実現できるようになりました。

このように、hooksを内部で使う関数の名前を「use」から始めて「useなんちゃら」関数と命名したもののことを「Custom Hooks」と呼びます。

この慣習に習って命名することでlinterがhooksの利用を検知し、助けを得ることができるようにみたいです。

最後に

こんな感じでとりあえずは手を動かして、大まかな挙動が確認できました。

これで、公式の「Hooks at a Glance」、「Using the State Hook」、「Using the Effect Hook」に書いてあることは一通りやりました。(少し省略していますが)

これからは、いろいろな記事や公式ページを確認して細かいことを確認していけたらなと思います。