『フロントエンドのデザインパターン』を読む会
README
読むもの
目的
フロントエンドのモダンな設計についての理解を深める。
頻出するパターンを知ることでアプリケーション全体の設計に活かせるはず。
進め方
参加者が交代で読む。
引っかかった点を話し合ったりコードを書いたりして完全理解してから進む。
どこまで読む等は決めずに時間内(1時間)で読めるところまでを読む。
今回は1回1チャプター程度で進めていくことになりそう。
2022-07-11(月) 20:00-21:00
実績
- 最初から
Chapter 01 訳者序
Chapter 02 はじめに
-
Chapter 03 シングルトンパターン
まで
次はどこから?
-
Chapter 04 プロキシパターン
から
MEMO
追記予定
開始前
suspenseの話 react queryとの兼ね合いや現在の採用状況
reactの記事が燃えていた話
本編
短い動画がある!
object.freese const readonly
weakmap weakptr
objectでやっているところに見るclassの必要性について
依存関係の隠蔽が理解するのに時間がかかった
global readonly はOKだけど mutableはカオス
変更される口を絞ることで
少なくともグローバルな状態が意図したとおりに変更されるようにできるのです
2022-07-18(月) 20:00-21:00
実績
-
Chapter 04 プロキシパターン
から
https://zenn.dev/morinokami/books/learning-patterns-1/viewer/proxy-pattern
次はどこから?
-
Chapter 05 プロバイダパターン
から
MEMO
Proxyって?
ターゲットオブジェクトとのやり取りをインターセプトし制御する
物事をインターセプトする
→バスケとかサッカーとか…
JavaScriptのProxyとReflect
ブラケット記法ではなくReflectを使う意味
Reflect は Proxy の作成を簡単にする組み込みのオブジェクトです。
殆ど同じ動きをするがProxyにおいてはReflectの方が使いやすい。
Mapやprivate field等エッジケースではReflectしか用いることができない。
使う意味
class定義する場合getter/setterで済ますことが多い。
変更できないglobal objectの挙動をwrapしたい場面で使えるのでは?
雑談
suspenseの話
2022-07-25(月) 20:00-21:00
実績
-
Chapter 05 プロバイダパターン
から
https://zenn.dev/morinokami/books/learning-patterns-1/viewer/provider-pattern
次はどこから?
-
Chapter 06 プロトタイプパターン
から
MEMO
providerはMUIやChakra等のthemeでよく見る
prop のバケツリレー (prop drilling)が把握し辛いという記述について
バケツリレーは渡す値を制限しながらであればいい部分もある
グローバルに同じオブジェクトを引き回していくことは頻繁には起きないはず
→component設計が大事そう
複数のコンポーネントを跨いだ状態の共有が容易になる
useContextを使う処理をhookに切り出すことでContextの指定ミスを防いだり、Provider外で使われた際の例外処理をまとめておける
HOCでよりシンプルに書ける
styledでthemeが引数に入る理由?
styled内でproviderから取ってきている(はず)
pros
グローバルな状態にアクセスできることのデメリットもあるはず
本当にグローバルなものに使うと可読性が向上する
cons
更新時にcontextを消費するコンポーネント全てが再レンダリングされる
link
プロバイダータワーの解消法
recoilを使う
recoilが読めない
コンポーネントの配列を受け取ってタワーにして返す
2022-08-01(月) 20:00-21:00
実績
-
Chapter 06 プロトタイプパターン
から
https://zenn.dev/morinokami/books/learning-patterns-1/viewer/prototype-pattern Chapter 07 コンテナ・プレゼンテーションパターン
次はどこから?
-
Chapter 08 オブザーバパターン
から
MEMO
追記予定
Chapter 06 プロトタイプパターン
プロトタイプに関数を追加することでどの実体からもアクセスできる
__proto__を再帰的に辿る
TypeScriptで使う場合
prototypeを追加した後、declere で型定義を追加する
classの必要性
classはprototypeの糖衣構文
他の言語から入るとclassのほうがまだ読みやすい
なんかprototypeと違って追加編集されなさそうに見える(実際はprototypeなのでされる)
Chapter 07 コンテナ・プレゼンテーションパターン
プレゼンテーションコンポーネントはステートを持たない(UI のためにステートが必要な場合を除き)
hook=コンテナコンポーネント
になる
2022-08-08(月) 20:00-21:00
実績
-
Chapter 08 オブザーバパターン
から
次はどこから?
-
Chapter 09 モジュールパターン
から
MEMO
observer=観測者
Observableオブジェクトを使ったパターンのこと。
- subscribe()/unsubscribe()メソッドでObservers(通知先配列)を管理
- notify()でObserversに通知
非同期に終了する処理のCallbackを纏めて書ける。
このような感じでobservableに対して複数のsubscribeを行うことができる。トリガーと通知後の処理を分離できることがメリット。
Observerの処理が多い・重い場合にパフォーマンスの問題が発生する可能性がある。
途中に出てきたRxJSの理解を深める
merge()内は起こったイベントによってtrue or falseを後続に渡すだけ
sample()の挙動はサンプリングのタイミングの制御だけで値は受け取ったものをそのまま次に渡しているだけみたい
雑談
ピザ2枚ルールの正しさを感じる。
MTGなどで喋る人は限られている、一つのチームで人を増やしてもパフォーマンスは上がっていかない。React.Context
この記事を読んでも理解できなかったので試した。
これのパターン2
この記事にあるレンダリングのトリガーが理解できてなかった
- Root
countの変更によって親が再レンダリングされるのでAppも再レンダリングされる - Root2
propsでchildrenを渡す=親で作成された要素が子にpropsとして渡されているだけなので、子が再レンダリングされてもpropsとして渡されたchildrenがそのまま表示され続けるだけ
countの変更では子(CountProvider)がレンダリングされるが、親からpropsとして渡されているAppに影響はない
この場合だと
- Root2(Appを使っているコンポーネント)でrenderのトリガーとなるuseStateを使っていない
- useStateをCountProviderに置くことでrenderがトリガーされた際に再レンダリングされる内容が存在しない
- childrenはあくまで静的なElementのpropsなので、propsを渡している親が変更タイミングを決定する
という整理で納得した。
ついでにRecoil含むVerをRoot3として書いてみて、Recoil使えばいいかなと思いました
2022-08-22(月) 20:00-21:00
実績
-
Chapter 09 モジュールパターン
から
次はどこから?
-
Chapter 10 ミックスインパターン
から
MEMO
基本的にはES2015(ES6)のmoduleの説明。
気づいたこと
- default exportは
.default
でアクセスできる -
*
でのすべてをインポートする手法はできるだけ用いない - Reactでも最小限のexportになるようにファイル分割されている
グローバルスコープの汚染を防いでカプセル化するための手法。
ダイナミックインポート
大きいモジュールを初期ロードで読み込むと通信量が多い、重い等デメリットがあるので使用時に読み込みたい。
個人的にはAngularのRoutingやwasmで見たことがあった。
Reactでの使用
2022-08-29(月) 20:00-21:00
実績
-
Chapter 10 モジュールパターン
から
次はどこから?
-
Chapter 11 メディエータ・ミドルウェアパターン
から
12のHOCが重そうなのでそちらの前半くらいまで行けたら…
MEMO
そもそも推奨されていない
バッドプラクティスとまで書かれている。
プロトタイプ汚染や拡張の見通しが悪くなるので辛そう。
継承すら使わないようにしようという流れなのにさらにカオスなものを好んで使うことはない。
その上でどう使うか
-
Object.assign()
でのClass.prototype
への機能拡張(classにmixinのobjectをassignする) -
Object.assign()
でのmixin
への機能拡張(mixinに別のmixinのobjectをassignする) -
__proto__
でのmixin
への機能拡張(mixinのobjectの__proto__
に別のmixinのobjectを指定する)
のような方法がある。
使用例としてはブラウザのWindow
オブジェクトで、Window
に対して様々なmixinが実装されている。
グローバルオブジェクトの独自拡張目的が主になりそう。
2022-09-05(月) 20:00-21:00
実績
-
Chapter 11 メディエータ・ミドルウェアパターン
から -
Chapter 12 HOC パターン
合成 まで
次はどこから?
-
Chapter 12 HOC パターン
フック から
MEMO
ミドルウェア
httpサーバー等でよく見る。
共通処理をまとめるのに使うことが多い。
ミドルウェアをもっと抽象的に表現したのがメディエータという理解。
同じ処理を通すという機構を作ることで複雑さを減らしている。
HOC
例として出てきているのはコンポーネントを引数にとって拡張したコンポーネントを返す関数。
基礎となるコンポーネントに対して様々な共通機能を追加することができる。
wrapすることで特定の処理を追加するイメージ。
例に載っているものは型を付けることが難しい作りになっているので、次のhooksを用いた例で解消されることを期待。
雑談
親コンポーネントをテストする際に、子コンポーネントをモックするべきか? with react-testing-library
結論としてはFAQの通りにユーザーインタラクションをテストするほうが良いのでモックは避けるべきとなった。
且つ上位コンポーネントを厚くテストすることが推奨されているので、下位コンポーネントの変更による多くのテストファイルの修正は許容する方針が良さそう。
interfaceや動きが変わってるならテストファイルも変えるべきという考えはしっくりくる。
2022-09-12(月) 20:00-21:00
実績
-
Chapter 12 HOC パターン
フック から -
Chapter 13 レンダープロップパターン
レンダープロップ まで
次はどこから?
-
Chapter 13 レンダープロップパターン
関数を子として渡す から
MEMO
フック
すべてのHOCパターンを置き換えるものではないが、フックで十分で可読性が上がることが多い。
一部のコンポーネントのみで使われたり、ある程度のカスタマイズが必要な場合はフックを使うメリットが大きい。
逆に独立した全体で使うようなロジックの場合はHOCのメリットが大きい。
どちらもDRYと関心の分離に有効。
propsにrenderする関数を渡す
jsxを返す関数をコンポーネントのpropsに渡し、コンポーネント内で描画することができる。
ただ描画するだけではなく、引数を元に描画する内容を決定する関数を渡すことでステートを持ち上げずに値をコンポーネント内で使用することができる。
tRPCの話
TypeScript依存なのでどこで使うんだろうと思いつつ、Railsみたいな使い方はできそうという話をした。
DBスキーマからフロントまで共通のモデルを使うことで初期の開発効率を上げていくイメージ。
2022-09-19(月) 20:00-21:00
実績
-
Chapter 13 レンダープロップパターン
関数を子として渡す から -
Chapter 14 フックパターン
まで
次はどこから?
-
Chapter 15 フライウェイトパターン
から
MEMO
レンダープロップパターン
HOC→レンダープロップ→フック と来たので今はフックを使えば良い。
フックが何を解決したのかという歴史を追う上では知っておいても良いパターン。
読むことはあるかもしれないが、新規に書くことは少なそう。
フック
今までフックで代替できるパターンを紹介してきてついに本丸。
ロジックの分割や再利用が容易に行えるようになった。
ステートを持つロジックの再利用が出来る。
サンプルのcodeSandboxが想定通りに動かなかったので理想形にしてみた。
ロジックが綺麗に分割されている。
標準フック
動きが変わるが、ちゃんと理解して使ってれば問題なさそうという話。
useReducerはuseStateの上位互換として使っていたので意図と異なる挙動をする部分も出てきそう。
とはいえuseReducerは大抵更新されたObjectを返しているので呼び出されたのに変更されないということはなく、Renderが走る回数も変わらないとは思う。
これを期に意識できるといい。
使ったこと無いフックあるなぁ…。
useImperativeHandle
、useDebugValue
は触ったことがなかった。
雑談
アウトプットしたいよな…。
何を書いたり喋ったりするのがいいんだろう?
gRPCの設計や用途の話、TypeScript Linterを自作した話。
2022-09-26(月) 20:00-21:00
実績
-
Chapter 15 フライウェイトパターン
から -
Chapter 16 ファクトリパターン
まで
次はどこから?
-
Chapter 17 複合パターン
から
MEMO
フライウェイトパターン
相変わらずサンプルコードが間違っているがcodesandboxは正しい。
共通のオブジェクトを見たり(マスタ扱い)、それをコピーすることでメモリ使用量を減らすためのパターン。
現代では積極的に使わない、というより下手に同じ参照を持って変更時に壊れるのが怖い。
ファクトリパターン
オブジェクトを一定のルールで作成する関数。
クラスのコンストラクタとの違いはほぼない。
ファクトリパターンは、比較的複雑で、設定により変更可能なオブジェクトを作成する場合に有効です。
テストパターンとか若干設定をカスタムさせたコンストラクタが欲しいがクラスは使いたくない時とかに使ったりする。
しかし、毎回新しいオブジェクトを作成するよりも、新しいインスタンスを作成する方が、メモリ効率が良い場合が多いです。
classメソッドにはprototypeチェーン回りでメモリ確保が少なくなる仕組みがあるのかもしれない。
2022-10-03(月) 20:00-21:00
実績
-
Chapter 17 複合パターン
から Chapter 18 コマンドパターン
-
Chapter 19 Learning JavaScript Design Patterns
まで
次はどこから?
読了!
MEMO
TBD
雑談
終了後に雑談したので話題だけ残しておく。
次に何を読むか
Learn Reactを読んでいく。
Reactのドキュメントを最初から読んだことがないので楽しみ。