Closed13

『フロントエンドのデザインパターン』を読む会

あけのあけの

README

読むもの

https://zenn.dev/morinokami/books/learning-patterns-1

目的

フロントエンドのモダンな設計についての理解を深める。
頻出するパターンを知ることでアプリケーション全体の設計に活かせるはず。

進め方

参加者が交代で読む。
引っかかった点を話し合ったりコードを書いたりして完全理解してから進む。
どこまで読む等は決めずに時間内(1時間)で読めるところまでを読む。

今回は1回1チャプター程度で進めていくことになりそう。

あけのあけの

2022-07-11(月) 20:00-21:00

実績

  • 最初から

https://zenn.dev/morinokami/books/learning-patterns-1

  • Chapter 01 訳者序
  • Chapter 02 はじめに
  • Chapter 03 シングルトンパターン まで

次はどこから?

  • Chapter 04 プロキシパターン から

https://zenn.dev/morinokami/books/learning-patterns-1/viewer/proxy-pattern

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 05 プロバイダパターン から

https://zenn.dev/morinokami/books/learning-patterns-1/viewer/provider-pattern

MEMO

Proxyって?

ターゲットオブジェクトとのやり取りをインターセプトし制御する

物事をインターセプトする
→バスケとかサッカーとか…

JavaScriptのProxyとReflect

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Proxy
https://ja.javascript.info/proxy

ブラケット記法ではなくReflectを使う意味

https://ja.javascript.info/proxy#ref-2183

Reflect は Proxy の作成を簡単にする組み込みのオブジェクトです。

殆ど同じ動きをするがProxyにおいてはReflectの方が使いやすい。
Mapやprivate field等エッジケースではReflectしか用いることができない。

使う意味

class定義する場合getter/setterで済ますことが多い。
変更できないglobal objectの挙動をwrapしたい場面で使えるのでは?

https://shizuka-na-kazushi.style/2020/09/20/where-use-javascript-proxy-you-should-know-earlier
https://zenn.dev/peaske/articles/38f1f7cce74dbc

雑談

suspenseの話
https://qiita.com/taro28/items/df91fc26b3ba461d9d5e
https://swr.vercel.app/docs/suspense

あけのあけの

2022-07-25(月) 20:00-21:00

実績

次はどこから?

  • Chapter 06 プロトタイプパターン から

https://zenn.dev/morinokami/books/learning-patterns-1/viewer/prototype-pattern

MEMO

providerはMUIやChakra等のthemeでよく見る

prop のバケツリレー (prop drilling)が把握し辛いという記述について
バケツリレーは渡す値を制限しながらであればいい部分もある
グローバルに同じオブジェクトを引き回していくことは頻繁には起きないはず
→component設計が大事そう

複数のコンポーネントを跨いだ状態の共有が容易になる

useContextを使う処理をhookに切り出すことでContextの指定ミスを防いだり、Provider外で使われた際の例外処理をまとめておける
HOCでよりシンプルに書ける

link

styledでthemeが引数に入る理由?
styled内でproviderから取ってきている(はず)

pros
グローバルな状態にアクセスできることのデメリットもあるはず
本当にグローバルなものに使うと可読性が向上する

cons
更新時にcontextを消費するコンポーネント全てが再レンダリングされる
link

プロバイダータワーの解消法

recoilを使う
recoilが読めない
https://zenn.dev/uhyo/articles/provider-tower-to-recoil

コンポーネントの配列を受け取ってタワーにして返す
https://qiita.com/fizumi6/items/d51625adc2a3ab7ac994

あけのあけの

2022-08-01(月) 20:00-21:00

実績

次はどこから?

  • Chapter 08 オブザーバパターン から

https://zenn.dev/morinokami/books/learning-patterns-1/viewer/observer-pattern

MEMO

追記予定

Chapter 06 プロトタイプパターン

プロトタイプに関数を追加することでどの実体からもアクセスできる
__proto__を再帰的に辿る

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create

TypeScriptで使う場合
prototypeを追加した後、declere で型定義を追加する

classの必要性

classはprototypeの糖衣構文
他の言語から入るとclassのほうがまだ読みやすい
なんかprototypeと違って追加編集されなさそうに見える(実際はprototypeなのでされる)

Chapter 07 コンテナ・プレゼンテーションパターン

プレゼンテーションコンポーネントはステートを持たない(UI のためにステートが必要な場合を除き)
hook=コンテナコンポーネントになる

あけのあけの

2022-08-08(月) 20:00-21:00

実績

  • Chapter 08 オブザーバパターン から

https://zenn.dev/morinokami/books/learning-patterns-1/viewer/observer-pattern

次はどこから?

  • Chapter 09 モジュールパターン から

https://zenn.dev/morinokami/books/learning-patterns-1/viewer/module-pattern

MEMO

observer=観測者
Observableオブジェクトを使ったパターンのこと。

  • subscribe()/unsubscribe()メソッドでObservers(通知先配列)を管理
  • notify()でObserversに通知

非同期に終了する処理のCallbackを纏めて書ける。
https://codesandbox.io/s/observer-pattern-2-forked-er96xe?file=/src/index.js
このような感じでobservableに対して複数のsubscribeを行うことができる。

トリガーと通知後の処理を分離できることがメリット。
Observerの処理が多い・重い場合にパフォーマンスの問題が発生する可能性がある。

途中に出てきたRxJSの理解を深める

https://codesandbox.io/s/observer-pattern-2-forked-ebfeq1?file=/src/index.js
コメントをつけた
merge()内は起こったイベントによってtrue or falseを後続に渡すだけ
sample()の挙動はサンプリングのタイミングの制御だけで値は受け取ったものをそのまま次に渡しているだけみたい

雑談

ピザ2枚ルールの正しさを感じる。
https://gigazine.net/news/20200809-too-many-small-teams/
MTGなどで喋る人は限られている、一つのチームで人を増やしてもパフォーマンスは上がっていかない。

React.Context

この記事を読んでも理解できなかったので試した。
https://zenn.dev/yuta_ura/articles/react-context-api

これのパターン2

この記事にあるレンダリングのトリガーが理解できてなかった
https://www.developerway.com/posts/react-elements-children-parents

https://codesandbox.io/s/compassionate-fire-00ytgp?file=/src/App.tsx

  • 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 モジュールパターン から

https://zenn.dev/morinokami/books/learning-patterns-1/viewer/module-pattern

次はどこから?

  • Chapter 10 ミックスインパターン から

https://zenn.dev/morinokami/books/learning-patterns-1/viewer/mixin-pattern

MEMO

基本的にはES2015(ES6)のmoduleの説明。
気づいたこと

  • default exportは.defaultでアクセスできる
  • *でのすべてをインポートする手法はできるだけ用いない
  • Reactでも最小限のexportになるようにファイル分割されている

グローバルスコープの汚染を防いでカプセル化するための手法。

ダイナミックインポート

大きいモジュールを初期ロードで読み込むと通信量が多い、重い等デメリットがあるので使用時に読み込みたい。
個人的にはAngularのRoutingやwasmで見たことがあった。
https://angular.io/guide/lazy-loading-ngmodules
https://zenn.dev/razokulover/articles/fb64150be7a667

Reactでの使用
https://ja.reactjs.org/docs/code-splitting.html

あけのあけの

2022-08-29(月) 20:00-21:00

実績

  • Chapter 10 モジュールパターン から

https://zenn.dev/morinokami/books/learning-patterns-1/viewer/mixin-pattern

次はどこから?

  • Chapter 11 メディエータ・ミドルウェアパターン から

https://zenn.dev/morinokami/books/learning-patterns-1/viewer/mediator-pattern

12のHOCが重そうなのでそちらの前半くらいまで行けたら…

MEMO

そもそも推奨されていない

https://zenn.dev/morinokami/books/learning-patterns-1/viewer/mixin-pattern#(es6-以前の)-react

バッドプラクティスとまで書かれている。
プロトタイプ汚染や拡張の見通しが悪くなるので辛そう。
継承すら使わないようにしようという流れなのにさらにカオスなものを好んで使うことはない。

その上でどう使うか

  • 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 パターン 合成 まで

https://zenn.dev/morinokami/books/learning-patterns-1/viewer/mediator-pattern

次はどこから?

  • Chapter 12 HOC パターン フック から

https://zenn.dev/morinokami/books/learning-patterns-1/viewer/hoc-pattern#フック

MEMO

ミドルウェア

httpサーバー等でよく見る。
共通処理をまとめるのに使うことが多い。
ミドルウェアをもっと抽象的に表現したのがメディエータという理解。

https://www.oodesign.com/mediator-pattern

同じ処理を通すという機構を作ることで複雑さを減らしている。

HOC

例として出てきているのはコンポーネントを引数にとって拡張したコンポーネントを返す関数。
基礎となるコンポーネントに対して様々な共通機能を追加することができる。
wrapすることで特定の処理を追加するイメージ。
例に載っているものは型を付けることが難しい作りになっているので、次のhooksを用いた例で解消されることを期待。

雑談

親コンポーネントをテストする際に、子コンポーネントをモックするべきか? with react-testing-library
https://testing-library.com/docs/react-testing-library/faq

結論としてはFAQの通りにユーザーインタラクションをテストするほうが良いのでモックは避けるべきとなった。
且つ上位コンポーネントを厚くテストすることが推奨されているので、下位コンポーネントの変更による多くのテストファイルの修正は許容する方針が良さそう。
interfaceや動きが変わってるならテストファイルも変えるべきという考えはしっくりくる。

あけのあけの

2022-09-12(月) 20:00-21:00

実績

  • Chapter 12 HOC パターン フック から
  • Chapter 13 レンダープロップパターン レンダープロップ まで

https://zenn.dev/morinokami/books/learning-patterns-1/viewer/hoc-pattern#フック

次はどこから?

  • Chapter 13 レンダープロップパターン 関数を子として渡す から

https://zenn.dev/morinokami/books/learning-patterns-1/viewer/render-props-pattern#関数を子として渡す

MEMO

フック

すべてのHOCパターンを置き換えるものではないが、フックで十分で可読性が上がることが多い。
一部のコンポーネントのみで使われたり、ある程度のカスタマイズが必要な場合はフックを使うメリットが大きい。
逆に独立した全体で使うようなロジックの場合はHOCのメリットが大きい。

どちらもDRYと関心の分離に有効。

https://reactjs.org/docs/hooks-faq.html
https://sbfl.net/blog/2020/08/21/use-react-hooks-easy/

propsにrenderする関数を渡す

jsxを返す関数をコンポーネントのpropsに渡し、コンポーネント内で描画することができる。
ただ描画するだけではなく、引数を元に描画する内容を決定する関数を渡すことでステートを持ち上げずに値をコンポーネント内で使用することができる。

tRPCの話

https://github.com/trpc/trpc

TypeScript依存なのでどこで使うんだろうと思いつつ、Railsみたいな使い方はできそうという話をした。
DBスキーマからフロントまで共通のモデルを使うことで初期の開発効率を上げていくイメージ。

あけのあけの

2022-09-19(月) 20:00-21:00

実績

  • Chapter 13 レンダープロップパターン 関数を子として渡す から
  • Chapter 14 フックパターン まで

https://zenn.dev/morinokami/books/learning-patterns-1/viewer/render-props-pattern#関数を子として渡す

次はどこから?

  • Chapter 15 フライウェイトパターン から

https://zenn.dev/morinokami/books/learning-patterns-1/viewer/flyweight-pattern

MEMO

レンダープロップパターン

HOC→レンダープロップ→フック と来たので今はフックを使えば良い。
フックが何を解決したのかという歴史を追う上では知っておいても良いパターン。
読むことはあるかもしれないが、新規に書くことは少なそう。

フック

今までフックで代替できるパターンを紹介してきてついに本丸。
ロジックの分割や再利用が容易に行えるようになった。
ステートを持つロジックの再利用が出来る。

サンプルのcodeSandboxが想定通りに動かなかったので理想形にしてみた。

https://codesandbox.io/s/hooks-5-forked-c9sr1n?file=/src/Input.js

ロジックが綺麗に分割されている。

標準フック

動きが変わるが、ちゃんと理解して使ってれば問題なさそうという話。
useReducerはuseStateの上位互換として使っていたので意図と異なる挙動をする部分も出てきそう。
とはいえuseReducerは大抵更新されたObjectを返しているので呼び出されたのに変更されないということはなく、Renderが走る回数も変わらないとは思う。
これを期に意識できるといい。
https://zenn.dev/dai_shi/articles/6e9a332f402d26

使ったこと無いフックあるなぁ…。
https://ics.media/entry/201106/

useImperativeHandleuseDebugValueは触ったことがなかった。

雑談

アウトプットしたいよな…。
何を書いたり喋ったりするのがいいんだろう?

https://findy.connpass.com/event/260644/
https://qiita.com/t_yano/items/7414c6b48f24ab3261da

gRPCの設計や用途の話、TypeScript Linterを自作した話。

https://grpc.io/
https://www.envoyproxy.io/
https://zenn.dev/meijin/scraps/04340d20070f71
https://c4se.hatenablog.com/entry/2021/11/24/141935
https://blog.sa2taka.com/post/custom-eslint-rule-with-typescript/

あけのあけの

2022-09-26(月) 20:00-21:00

実績

  • Chapter 15 フライウェイトパターン から
  • Chapter 16 ファクトリパターン まで

https://zenn.dev/morinokami/books/learning-patterns-1/viewer/flyweight-pattern

次はどこから?

  • Chapter 17 複合パターン から

https://zenn.dev/morinokami/books/learning-patterns-1/viewer/compound-pattern

MEMO

フライウェイトパターン

相変わらずサンプルコードが間違っているがcodesandboxは正しい。
共通のオブジェクトを見たり(マスタ扱い)、それをコピーすることでメモリ使用量を減らすためのパターン。
現代では積極的に使わない、というより下手に同じ参照を持って変更時に壊れるのが怖い。

ファクトリパターン

オブジェクトを一定のルールで作成する関数。
クラスのコンストラクタとの違いはほぼない。

ファクトリパターンは、比較的複雑で、設定により変更可能なオブジェクトを作成する場合に有効です。

テストパターンとか若干設定をカスタムさせたコンストラクタが欲しいがクラスは使いたくない時とかに使ったりする。

しかし、毎回新しいオブジェクトを作成するよりも、新しいインスタンスを作成する方が、メモリ効率が良い場合が多いです。

classメソッドにはprototypeチェーン回りでメモリ確保が少なくなる仕組みがあるのかもしれない。

あけのあけの

2022-10-03(月) 20:00-21:00

実績

  • Chapter 17 複合パターン から
  • Chapter 18 コマンドパターン
  • Chapter 19 Learning JavaScript Design Patterns まで

https://zenn.dev/morinokami/books/learning-patterns-1/viewer/compound-pattern

次はどこから?

読了!

MEMO

TBD

雑談

終了後に雑談したので話題だけ残しておく。

次に何を読むか

https://beta.reactjs.org/

Learn Reactを読んでいく。
Reactのドキュメントを最初から読んだことがないので楽しみ。

このスクラップは2022/10/03にクローズされました