
2025.03.19
急成長するドバイ不動産市場の今 投資のチャンスと注意点を専門家が解説
読解 Flutter Hooks(全1記事)
リンクをコピー
記事をブックマーク
Kyohei Ito氏:「読解Flutter Hooks」というタイトルで、発表します。簡単に自己紹介です。伊藤恭平と言います。GitHubやTwitterでは、KyoheiG3という名前で活動しています。主にiOSのアプリの開発をやっていますが、だいたい4、5ヶ月くらい前からFlutterをやり始めました。
今日の内容ですが、Hooksの使い方などはやらずに、Hooksの動きを理解するところを目標にしようかと思っています。そのため、今日の発表は、コードが多めになってしまいますが、よろしくお願いします。
簡単にHooksの説明というか、振り返りをします。もともとはReact.jsの16.8、19年2月以降に追加された機能で。Flutterにも、有名なRemi Rousseletさんが、2018年12月に初回コミットしていました。
「どうしてHooksを使ったほうがいいの?」という話ですが、ExampleというReactのコンポーネント。これはJSのコードです。
見たらなんとなくわかると思いますが、Exampleというclassを定義して、その中でstateというオブジェクトを作って。下のほうを見ていくと、ボタンをクリックしたらその中でsetStateを呼び出して、stateのcountを+1しているような実装がなんとなくわかるのではないかと思います。
次は、Hookを使った実装です。useStateを使っていますが、一番大きな違いとしては、Example、classで定義されていたものがfunctionに変わっています。そのfunctionの中で、useStateをconstで定義して、returnの中はほぼ一緒ですが、onClickの中でsetCountを呼び出して、countを+1するような感じになっています。
Hooksを使うと、状態の管理などをclassを使わず、単体で行えるようになります。Flutterをやっている方ならピンとくると思います。Flutterも同じような実装があるというか。Reactコンポーネントのclassの部分がいわゆるStatefulWidgetで、functionの実装がStatelessWidgetになるんじゃないかと思います。
これが今言ったとおりです。Flutterで書くと、Example、classでStatefulWidgetで定義して、Stateの中でCountを持って、buildの中でボタンを押したらsetStateを呼んで、countを+1する。
それをStatelessWidgetでHooksを使う。これ、HookWidgetをStatelessWidgetと読み換えてもらって。buildの中でuseStateを定義して、ボタンを押したらcountを1+する。
このように、状態の管理などをStatefulWidgetを使わず、同じように単体で行えました。実際どういう動き、どういう仕組みになっているのかです。readmeを見ると、こんなソースコードが書いてあります。ちょっと要領を得ないというか、難しいというか(笑)。抽象化されすぎていて難しいので、実際の中のコードを読んでみましょう。主な登場人物として、HookWidgetとHookElementが出てきます。
先ほどのExampleのStatelessWidgetの例です。Exampleのソースコード、class自体はHookWidgetを継承しています。そのため、HookWidgetの中身を見てみると、普通にStatelessWidgetで宣言されていて、createElementというメソッドでStatelessHookElementをreturmしています。
StatelessHookElementはHookElementのmixinを適用しているので、その中を見ると、これもめちゃくちゃソースコードを端折っていますが、メインとなるのはこのbuildというメソッドの中。
buildのメソッドの中は何をやっているかと言うと、Hooksという配列からオブジェクトを取り出しています。1発目にnullが入りますが、その直後にcurrentHookElementに自分自身を突っ込んで、tryの中でsuperのbuildを呼び出す。その直後、finallyの中で、currentHookElementにnullを突っ込んでいると。
どういうことかと言うと、要するにsuperのbuildを呼び出している間だけstaticの変数のcurrentHookElementに自分自身を突っ込んでいます。呼び出しが終わったら、nullを入れて参照できないようにしています。
またExampleのclassに戻ります。実際にbuildしているuseStateの中を、ちょっと見てみたいと思います。これもチョイチョイ端折っていますが、useStateは中でuseというメソッドを呼び出して、引数としてStateHookのインスタンスを渡しています。
useは何を呼び出しているかと言うと、Hookのstaticメソッドです。その中で先ほど出てきたcurrentHookElementを参照して、その_useというメソッドを呼び出しています。currentHookElementには先ほどのbuildを実行中のelementが入っているため、_useを問題なく呼び出せます。
では_useはどうなっているのか。これは、先ほどのHookElementの中身です。_useの中で、currentHookStateは1回目はnullが入っているため、if文が3つあるうちの一番上に入ってきて。createHookStateをして、それを変数に保持して、Hooksにそれ自身を追加しています。
if文はいったんスルーしてもらって、下のほうでHookStateをbuildして、その結果をresultとして返しています。ちなみに、とばしたif文の中身が何かと言うと、ランタイムタイプが違っていたらデバック時にしか基本的に起こり得ませんが、デバックだと、ホットリロード的なことを行うと、ランタイムタイプが変わってしまう可能性がある。
実装で、例えばuseStateを違うHookに変えてしまった場合に起こり得ますが、リリースビルドの時にもしここに入ってしまったら、処理が落ちるようになっています。次は“実際に引数に渡されている値が変わった”というif文ですが、その時は普通にアップデートされたり、Stateがもう1回作り直されたりする処理が走るようになっています。
useStateの中にグローバルのuseが使われているなど、ちょっと回りくどい実装になっていたと思います。HookWidget自体にuseのメソッドがあれば解決しそうな気がしますが、遠回りの処理をしている理由の1つとして、HookBuilderの存在があるのではと。
HookBuilderはHookWidgetを継承しています。先ほどのExampleのclassではHookWidgetを継承していましたが、あそこはStatelessWidgetなどを使ったときに、useのHooksのメソッドを呼び出すためのクロージャーを実行するWidgetになっています。
こういう実装にしておくと、build中のelementをどこでも参照できる状態になります。例えばuseContextというメソッドがあります。これもグローバルでどこからでも呼べますが、build中であれば持っているcurrentHookElementをreturnして、Contextを参照するという、便利なこともできるようになっています。
ここまでがだいたいWidgetの中身です。HookとHookStateが、実際にuseメソッドの実態になります。ここからは、先ほどから出てきているuseStateをちょっと見てみたいと思います。
これもuseを呼び出し、StateHookを作って呼び出しています。StateHookは何をやっているかと言うと、Hookのclassを継承して、イニシャルデータを保持して、createStateを作って返しています。
HookStateを継承していますが、この中ではinitHookでValueNotifierを作ってaddlistenerして。listenerが呼ばれたらsetStateを実行して、その下でdisposeが呼ばれたときに、そのstateをdisposeするような実装になっています。
これらのライフサイクル以外にも、いろいろなライフサイクルのメソッドがありますが、このあたりはreadmeを見てもらえればわかると思います。例えば、下から4つ目くらいにmarkMayNeedRebuildというメソッドがありますが、こういうメソッドをStateの中で呼ぶと、実際にWidgetがRebuildされる処理も行えるようになります。
最初から用意されているHooksもいくつかありますが、そのあたりもreadmeを見てもらえればと思います。
あとはCustom Hookです。Hookを自分で作れて、その作り方ですが、大きく2つ。classとfunctionを使って作れます。FixedExtentScrollControllerというものの、Hookがなかったので用意してみたんですけれども。
useStateと一緒ですね。initialでItemを受け取って、createStateでHookStateを継承しているclassを返す。initHookの中でFixedExtentScrollControllerのインスタンスを作って、buildというメソッドでcontrollerをreturnして、disposeが呼ばれたらcontrollerをdisposeするような処理を書けば完成です。
メソッドが直接呼ばれないようにするために、グローバルに一応1つメソッドを用意して、そこから呼び出すような処理にするといいかと思います。
あともう1つ、これもreadmeから持ってきましたが、functionでHookを作れます。メソッドの中で、ほかにもうすでに用意されているHookのメソッドを使って、Hookを作れるのです。これは、useStateを使って、その値が変わったときにログを吐き出すHookになっています。
一応いくつかルールがあるため、簡単に説明すると、名前は、useというプレフィックスを使いましょうとなっています。ここは決まりのようなものです。
あとは、Hookを使うときに、buildの条件分岐の中でuseを呼び出すことは禁止されています。これはelementに配列でHookが保持されている状態ですが、if文で配列の呼び出しの順番が変わってしまうと処理がおかしくなってしまうので、これはNGになっています。
あとはホットリロードについてです。ホットリロードも基本的にデバック中であれば普通に動くように作られていて。例えばこういうuseA、B、Cみたいなメソッドを順番に呼ぶような実装にしていたとして。開発の途中で、0というuseBの引数を変えたとしても、特に問題なく値が保持され、動かせるようになっています。
useBの実装がいらなかったからと途中で消してしまった場合は、useAの値は参照が保持されたままになりますが、useCに関しては値が破棄され、もう1回新しくStateが作り直されます。
以上です。ありがとうございました。
関連タグ:
2025.03.21
マネージャーの「自分でやったほうが早い」という行動で失うもの 効率・スピード重視の職場に足りていない考え方
2025.03.17
不確実な時代だからこそ「知らないこと」を武器にする ハーバード首席卒業生の逆説的なメッセージ
2025.03.19
部下の「タスクの先延ばし」が少ない上司の特徴とは? 研究が示す、先延ばし行動を減らすリーダーの条件
2025.03.17
いくら読書をしても「成長しない人」が見落としていること 10分でできる「正しい学び方」
2025.03.19
組織をダメにする“害虫”の正体は間違った思い込み AIやDXなど手段のみにこだわるダメ上司の見極め方
2025.03.19
フェデラー氏が語る「ただの1ポイント」の哲学 ウィンブルドン敗北から学んだ失敗からの立ち直り方
2025.03.18
フェデラー氏が語る「努力しない成功は神話」という真実 ダートマス卒業生に贈る勝利の秘訣
2025.03.18
全知全能の最先端AI「Cristal」が企業の大脳となる ソフトバンク孫正義氏が語る、現代における「超知性」の可能性
2025.03.18
部下に「そうかなぁ?」と思われない1on1の問いかけ エンゲージメントを高めるマネジメントに欠かせない「聴く」技術
2025.03.19
OpenAIのAIエージェント「Deep research」はビジネスをどう変革するのか? サム・アルトマン氏ら4人がデモンストレーション
2025.03.21
マネージャーの「自分でやったほうが早い」という行動で失うもの 効率・スピード重視の職場に足りていない考え方
2025.03.17
不確実な時代だからこそ「知らないこと」を武器にする ハーバード首席卒業生の逆説的なメッセージ
2025.03.19
部下の「タスクの先延ばし」が少ない上司の特徴とは? 研究が示す、先延ばし行動を減らすリーダーの条件
2025.03.17
いくら読書をしても「成長しない人」が見落としていること 10分でできる「正しい学び方」
2025.03.19
組織をダメにする“害虫”の正体は間違った思い込み AIやDXなど手段のみにこだわるダメ上司の見極め方
2025.03.19
フェデラー氏が語る「ただの1ポイント」の哲学 ウィンブルドン敗北から学んだ失敗からの立ち直り方
2025.03.18
フェデラー氏が語る「努力しない成功は神話」という真実 ダートマス卒業生に贈る勝利の秘訣
2025.03.18
全知全能の最先端AI「Cristal」が企業の大脳となる ソフトバンク孫正義氏が語る、現代における「超知性」の可能性
2025.03.18
部下に「そうかなぁ?」と思われない1on1の問いかけ エンゲージメントを高めるマネジメントに欠かせない「聴く」技術
2025.03.19
OpenAIのAIエージェント「Deep research」はビジネスをどう変革するのか? サム・アルトマン氏ら4人がデモンストレーション
青木耕平さんとザッソウ(#156〜158)
2025.02.05 - 2025.03.19
片付けパパ対談【特別編】豊かな人生を過ごすための「投資」&「交渉術」 ~チャンスを逃さず信頼関係も育むコツ~
2025.02.10 - 2025.02.10
グローバルの経営理論に学ぶ、企業アルムナイ成功への示唆〜中央大学ビジネススクール 犬飼知徳教授
2025.02.18 - 2025.02.18
【手放すTALK LIVE#046】 出版記念イベント 『大きなシステムと小さなファンタジー』 一つ一つのいのちが大切にされる社会へ
2025.02.03 - 2025.02.03
「聴く」から始まる組織変革 〜篠田真貴子さんと考える対話型マネジメント〜
2025.02.14 - 2025.02.14