2024.12.19
システムの穴を運用でカバーしようとしてミス多発… バグが大量発生、決算が合わない状態から業務効率化を実現するまで
React HooksとReduxとProxy(全1記事)
リンクをコピー
記事をブックマーク
Daishi Kato(@dai_shi)氏:よろしくお願いします。「React HooksとReduxとProxy」というタイトルで発表します。
自己紹介をさせていただきます。加藤大志といいます。
今、フリーランスプログラマーで、仕事募集中の状態です。最近はTwitterをがんばっていまして、TwitterとMediumとGitHubにいろいろ書いています。
React自体は「0.14」から使い始めました。最初に出てきた頃……createClassが出てきた時は、ぜんぜん魅力を感じませんでしたが、0.14からfunction componentsが使えるようになって、非常に魅力的に感じて使い始めました。
その時は「function componentsだけで書きたい」と思っていました。Reduxの相性がすごくよかったので、はじめはReduxで「もうLocal stateは一切使わないで、全部Global stateに入れてしまえ」というスタイルを採用していました。
React Hooksが出たわけですが、React Hooksはfunction componentsですべてが完結する仕組みです。もともとの経緯がそうなので、とても歓迎しています。
0.14が出たときにも「もうすぐできるよ」と言われていて、しばらく待ったらすぐにできるかなと思って、Reduxでがんばっていましたが、実際はだいぶかかりましたね。やっとReact Hooksが出てきて、晴れてfunction componentsだけで書けるようになって、うれしいかぎりです。
React Hooksが好き過ぎて、小さいライブラリをたくさん作っています。今は6個ぐらい作っていて、今日はそのうちの「react-hooks-easy-redux」というライブラリについて紹介します。
そもそもReduxとReact Reduxは分けて考えるもので、Redux自体は独立した、Reactとは関係のないライブラリになっています。実際、99行で実装できるくらい小さいです。最初は本当に小さかったなと思います。
一方で、React ReduxはReduxとつなげるバインディングライブラリになっています。これは非常に複雑というか、Reactの中でReduxを使うためにパフォーマンスチューニングされています。
ただ、そのパフォーマンスをきちんと理解して使うにはObject Identityやselectorなどの理解が必要で、初心者にはちょっと難しいなと思います。例えば、Reactが初めての人に教えるとき、そこがないと進まないのはちょっとつらいなと感じたことがありました。React Reduxのパフォーマンスのよさはあると思いますが、別の手があってもいいんじゃないかなと思っていました。
そして、React Hooksが登場してから、いろんな人がReduxの代替ライブラリのようなものを一生懸命作っています。
2つぐらいタイプがあって、1つは、Reduxを使わずにHooksだけでなんとなく似たようなことをするというものです。もう1つは、Reduxを使いつつ、React Reduxは使わずに、それに代わるバインディングをHooksで実現するというものです。私はどっちもやっていますが、今日紹介するのは後者のほうです。
ここまでが導入で、残りは、(スライドを指して)だいたいこれが一般的にどうやって実装されているかという紹介と、その問題点を示して、解決策の候補と、Proxyを使った解決策をご紹介しようと思います。
まず導入として、ReduxのStoreが普通に作られる感じをイメージしてください。stateにcounterの数字とtextの文字列があるRedux Storeを作ったとします。
これをHooksで使ったときの1つのイメージが(スライドを指して)こちら。Counterコンポーネントがあって、stateを取ってくるhookとdispatchを取ってくるhookがあって、コールバックを作って、そのstateを表示したり、そのコールバックをイベントから呼び出したりするように書きます。
countとtextが2つ、stateの中に入っているんですけど、普通に何事も考えずにやると、このコンポーネントではCounterしか使っていないにもかかわらず、state.textが変更された場合もレンダリングされてしまいます。
ちなみに、先ほどの例を実現する素朴な実装は(スライドを指して)こんな感じです。それぞれのHooksの実装……といっても1個しかないですが、こんな感じで作ります。あとでまた資料を公開するので、見ていただけたらと思います。
ただ、これは参考程度というか、実際にこのまま使うことはありません。いろんな問題点があるので、使わないです。
先ほど言いましたが、そもそも「変更検知問題」というものがあります。
Redux stateは、一般的には、アプリに大きく1個のGlobal stateを作るんですけれど、その一部の変更によって、ぜんぜん関係ないコンポーネント、stateの一部の使わないコンポーネントまでレンダリングすることは避けたい、という問題があります。
一方で、仮にすごく小さいアプリや限定的にReduxを使っている場合で、パフォーマンスがそんなに問題にならなければ、先ほどのような素朴な実装でもそこまで問題ないです。アプリの形態によると思いますけど、問題にならないこともあります。
解決法としては、selectorを指定する方法と、memoizeする方法と、auto-detectする方法があると思います。ほかにもあるかもしれませんが、今日はauto-detectを採用するかたちです。一応、ほかの方法も紹介しておこうと思います。
selectorは、いわゆるReact Reduxのconnectを使ったもので、ただそのままなんですけど、stateから部分集合を取り出すようなselectorの関数をhookに渡して、部分集合を取り出してそれを使う。この部分集合に該当しない場合はレンダリングしないという作り方をします。これが一番シンプルですね。
(スライドを指して)これはmemoizationを使ったケースです。全部取ってきてしまうけれど、変わった部分や自分が使うとわかっている部分を、input arrayで渡してメモする。それによって、実際は一瞬だけrender関数が実行されるんですけど、そこまでひどくないというか、パフォーマンスはそこそこ出ます。
これは完全ではないかもしれないです。ちょっと見にくいかなというところはありますし、あまり一般的ではなく、提案されているようなやり方ではないです。
最後のauto-detectですが、これは先ほど紹介した使い方と一緒です。stateを丸々持ってきて、stateのcounterを表示するだけのレンダリングで、解決策1でselectorを指定したものと同じような動作をしようというものです。
「そんなことができるか?」という話なんですけど、Proxyというものがあって、オブジェクトの操作をトラップして処理を行います。
これを使うと、そのstateの中のどこか一部分が読まれて……または書かれてでもいいんですけど、そこが触られたときに、触られたということを記録しておいて、あとでstateから変更されたときに「触られたところに該当するかどうか」で、レンダリングするかしないかを判断できます。
このアプローチを採用してみようということで、先ほど紹介したライブラリ「react-hooks-easy-redux」を作りました。
1個だけ、依存ライブラリになるものが入っていて、proxyequalというライブラリです。Proxy自体は、1個のオブジェクトに対して適用するんですけど、それを深いオブジェクトに対して再帰的に適用してくれるものです。(スライドを指して)実際に、これを作りました。
Proxyは一応コストがかかるので、どれぐらいコストがかかるのかなと思ってベンチマークテストをしました。と言っても、たった1個のシンプルなベンチマーク用のアプリを使って動かしているだけなので、これがすべてではないんですけど、一例としては(スライドを指して)こうなります。
スライドの左上に出ているReact Redux v5.0.7の例が評価対象で、FPSが50ぐらいです。それに対して、今回私が作ったreact-hooks-easy-reduxのv0.8.0は、FPSが8.37。実際に触ってもわかるぐらい遅くなって、パフォーマンスが出ないという問題がありました。
いろいろと調べていったところ、先ほどご紹介したproxyequalの依存ライブラリに問題があることがわかりました。そして、proxyequalの作者と一緒にそのボトルネックを解消して、新しいバージョンを作って、今は38.96ぐらいのFPSが出るようになっています。
体感でももちろんわかるんですけど、もとから比べれば断然「マシ」です。これなら利用に堪えられるかなくらいにはなっていますね。
これで終わりなんですが、興味のある方はぜひ使ってみてください。
Reduxを使って、さっきみたいに簡単に書けるのかとか、custom hooksはどんなものなのかとか、ベンチマークテストをもっとやってみたいとか、そういう方がいらしたら、ぜひ見てみてください。
以上で発表を終わります。ありがとうございました。
(会場拍手)
関連タグ:
2024.12.20
日本の約10倍がん患者が殺到し、病院はキャパオーバー ジャパンハートが描く医療の未来と、カンボジアに新病院を作る理由
2024.12.19
12万通りの「資格の組み合わせ」の中で厳選された60の項目 532の資格を持つ林雄次氏の新刊『資格のかけ算』の見所
2024.12.16
32歳で成績最下位から1年でトップ営業になれた理由 売るテクニックよりも大事な「あり方」
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
PR | 2024.12.20
モンスター化したExcelが、ある日突然崩壊 昭和のガス工事会社を生まれ変わらせた、起死回生のノーコード活用術
2024.12.12
会議で発言しやすくなる「心理的安全性」を高めるには ファシリテーションがうまい人の3つの条件
2024.12.18
「社長以外みんな儲かる給与設計」にした理由 経営者たちが語る、優秀な人材集め・会社を発展させるためのヒント
2024.12.17
面接で「後輩を指導できなさそう」と思われる人の伝え方 歳を重ねるほど重視される経験の「ノウハウ化」
2024.12.13
ファシリテーターは「しゃべらないほうがいい」理由 入山章栄氏が語る、心理的安全性の高い場を作るポイント
2024.12.10
メールのラリー回数でわかる「評価されない人」の特徴 職場での評価を下げる行動5選
Climbers Startup JAPAN EXPO 2024 - 秋 -
2024.11.20 - 2024.11.21
『主体的なキャリア形成』を考える~資格のかけ算について〜
2024.12.07 - 2024.12.07
Startup CTO of the year 2024
2024.11.19 - 2024.11.19
社員の力を引き出す経営戦略〜ひとり一人が自ら成長する組織づくり〜
2024.11.20 - 2024.11.20
「確率思考」で未来を見通す 事業を成功に導く意思決定 ~エビデンス・ベースド・マーケティング思考の調査分析で事業に有効な予測手法とは~
2024.11.05 - 2024.11.05