インターラプト開発者ブログ

インターラプトのプロダクト・サービスに関する開発ブログ

Reactで気づいたらすべてがuseになっていた話

ReactはHooksが導入される前から書いていました。同時はconstでコンポーネントを定義するのではなく、class構文で書いていました。今ネットで検索してもclass構文で、stateへのセットもthis.setStateでした。 パフォーマンス改善と利便性のために、constructorには大量の.bindが並ぶそんなコードでした。

class構文からconst定義の関数型コンポーネントになった

コンポーネントが、React.FC型によって関数型のコンポーネントになり、classを定義しなくてもconstで変数を定義するようにコンポーネントを実装出来るようになりました。

setStateがuseStateになった

class構文の時はstateをclassに定義し、初期化を行いthis.setStateでstateの値を変更し、stateを定義する場所が決まっています。setStateするときに、どのstateだっけと定義を見に行ったりしていました。

const [mikan, setMikan] = useState(null);

新しい書き方では、配列の分割代入を使う形になっていて、配列の1番目にはstateそのものの変数、二番目にはstateに代入するための関数が返ります。

初期化処理などはuseEffectになった

当時は初期化処理などは componentDidMount と componentDidUpdate を使っていました。しかし自分は直接renderメソッドに実装を書いてしまっていた記憶があります。非常に良くない書き方をしていました。そもそもメソッドが分かれていたので、双方の関数でデータをやり取りするにはthisを使う必要があり 変更のあったpropsを判別するにはifやswitchで判別する必要がありました。

そのため、非常に煩雑な実装になるため、できるだけreact-reduxのほうに書いたり、renderに書いたりしてしまっていました。

しかし、そんなReactの書き方はもうおしまい! useEffect でも描けるようになりました。

特に嬉しいのは使い勝手がrenderメソッドに直接書いているような感覚で使えることです。ロジックがあれば、それをuseEffectで包めばよいです。第二引数に[] を指定すると、componentDidMount、propsの一部のフィールドを配列で渡すと、componentDidUpdate相当になります。propsのフィールドが更新されたときにuseEffectの第一引数のコールバック関数が再実行されます。

また、useEffect内でreturnで関数を返せば componentWillUnmount相当の処理をしてくれます。

useMemoが便利

useMemoは、何度も繰り返されるライフサイクルの中で、第二引数の配列に渡されたpropsのフィールドの値が変わっていなければ、前回実行した値を使いまわす、キャッシュ機能を持つHookです。挙動としてはuseEffectと一緒で、ただreturnで値を返すことが違います。

便利だからとrender内でついついロジックを書いて変数に代入をしてしまっている場所があれば全てuseMemoに置き換えると良いです。

ただ注意が必要で、useMemoはコンポーネントさえもキャッシュにすることが出来ますが、明示的に再レンダリングさせたいと言った目的がなければ、単純に別コンポーネント化してしまったほうが良いです。コンポーネントの中身が単純なjQueryなどによるDOM相当を行っていて何度も再レンダリング行われてしまったりする場合などは例外的にコンポーネントにたいして使っても良いと思います。

onClickなどの関数はuseCallbackへ

class構文では、onClickに渡す関数はclassのconstructorでthisが使えるようにbindしていました。claasのメソッドなので、thisで定義されたpropsなstateしか呼び出せず、クロージャの変数が使えず、かといってrenderで書くと何度も関数が再定義されたり、クロージャの変数の扱いなどで何かとトラブルの原因になっていました。

それも直接useCallbackを使う事で、関数内に定義できるようになりました。useEffect同様関数自体をキャッシュしてくれるので、第二引数の変数が更新されるまでは中の関数の変数は不変なので、安心してクロージャの変数が使えます。

まとめ: 気づいたらuseで包まなくていい物がなくなった

useを適切に使うと全てがuse系に包まれて、リアクティブな状態になりました。プログラムは何かしたのイベントにより発動し、連鎖的につながって一つの処理が行われていきます。

もし手元に既存の手続き型のレガシーなコードがあったら、一つ一つのロジックを分解してuse系で包み込んでいくだけで、リアクティブなプログラムにリファクタリングすることが出来ます。

どこに書かないと行けないといったコーディングルールを理解する必要は無く、ドミノ倒しやマインクラフトの全自動マシンのように、連鎖反応を起こす仕組みさえ考えるだけでいいのです。