Slide 1

Slide 1 text

propsのバケツリレー対策で Global Stateを使うその前に… フロントエンドLT新年会 2023.1.18 taro(@taroro_tarotaro)

Slide 2

Slide 2 text

自己紹介 ● taro( @taroro_tarotaro) ● シェルフィー株式会社で建設SaaSを作ってます!(2020.11〜) ● React, TypeScript, Server Side Kotlin ※Reactしか触ったことがないため、Reactをベースとした話になります🙏

Slide 3

Slide 3 text

はじめに

Slide 4

Slide 4 text

はじめに 昨今よく言われるReactのstateの分類 1. Server Data Cache 2. Global State: 1を除くページをまたいで保持し続ける必要のあるstate 3. Local State: ページをまたいで保持する必要のないstate https://zenn.dev/yoshiko/articles/607ec0c9b0408d

Slide 5

Slide 5 text

はじめに 昨今よく言われるReactのstateの分類 1. Server Data Cache ○ TanStack Query, swr, etc. 2. Global State: 1を除くページをまたいで保持し続ける必要のあるstate ○ useContext, Recoil, Jotai, Redux, Zustand, etc. 3. Local State: ページをまたいで保持する必要のないstate ○ useState, etc.

Slide 6

Slide 6 text

はじめに 昨今よく言われるReactのstateの分類 1. Server Data Cache ○ TanStack Query, swr, etc. 2. Global State: 1を除くページをまたいで保持し続ける必要のあるstate ○ useContext, Recoil, Jotai, Redux, Zustand, etc. 3. Local State: ページをまたいで保持する必要のないstate ○ useState, etc. 💡Local Stateを実装的都合でGlobal Stateの管理手法を使う時の話

Slide 7

Slide 7 text

はじめに Local Stateを実装的都合でGlobal Stateの手段で管理する時の話 ● どんなケースか ● その場合のむずかしさ ● ケース別にLocal Stateでうまくやる方法 ※変更頻度が多く複数人で触るようなComponentを前提としています🙇

Slide 8

Slide 8 text

実装的にGlobal Stateで 管理したくなるケース

Slide 9

Slide 9 text

実装的にGlobal Stateで管理したくなるケース ● 子、孫Component間でstateを共有したい ● propsのバケツリレー(props drilling)を避けたい ● 子Component内のstateを親Componentから制御したい など →Global Stateで管理してもよいがむずかしさがある

Slide 10

Slide 10 text

Global Stateで管理する時の むずかしさ

Slide 11

Slide 11 text

Global Stateで管理する時のむずかしさ ● スコープが広がる ○ まぁGlobalだからね(Atoms系だと違うかも) ● データフローが見えづらくなる ○ 子Componentのpropから消えるため ● ライフタイムが伸びる ○ これの考慮が結構忘れがち ○ クリーンアップ忘れて変更前のstateがチラっと見えちゃう🫣

Slide 12

Slide 12 text

Global Stateで管理する時のむずかしさ ● スコープが広がる ○ まぁGlobalだからね(Atoms系だと違うかも) ● データフローが見えづらくなる ○ 子Componentのpropから消えるため ● ライフタイムが伸びる ○ これの考慮が結構忘れがち ○ クリーンアップ忘れて変更前のstateがチラっと見えちゃう🫣 →影響範囲の把握コストが増える

Slide 13

Slide 13 text

Global Stateで管理する時のむずかしさ ● スコープが広がる ○ まぁGlobalだからね(Atoms系だと違うかも) ● データフローが見えづらくなる ○ 子Componentのpropから消えるため ● ライフタイムが伸びる ○ これの考慮が結構忘れがち ○ クリーンアップ忘れて変更前のstateがチラっと見えちゃう🫣 →影響範囲の把握コストが増える →僕はLocal Stateでがんばる派でその方法を紹介していく

Slide 14

Slide 14 text

Local Stateで うまくやる方法

Slide 15

Slide 15 text

Local Stateでうまくやる方法 実装的にGlobal Stateで管理したくなるケース ● 子、孫Component間でstateを共有したい ● propsのバケツリレー(props drilling)を避けたい ● 子Component内のstateを親Componentから制御したい

Slide 16

Slide 16 text

Local Stateでうまくやる方法 実装的にGlobal Stateで管理したくなるケース ● 子、孫Component間でstateを共有したい ● propsのバケツリレー(props drilling)を避けたい ● 子Component内のstateを親Componentから制御したい

Slide 17

Slide 17 text

Local Stateでうまくやる方法 ①まずは基本のLifting State Up 「当たり前だろ!」と言われるかもしれないが、 親に持ち上げてstateの持ち方を変えるだけで意外と解決したりする。

Slide 18

Slide 18 text

Local Stateでうまくやる方法 ①まずは基本のLifting State Up 「当たり前だろ!」と言われるかもしれないが、 親に持ち上げてstateの持ち方を変えるだけで意外と解決したりする。 →「いやいやそうするとpropsをバケツリレーしないといけないんよ…」

Slide 19

Slide 19 text

Local Stateでうまくやる方法 実装的にGlobal Stateで管理したくなるケース ● 子、孫Component間でstateを共有したい ● propsのバケツリレー(props drilling)を避けたい ● 子Component内のstateを親Componentから制御したい

Slide 20

Slide 20 text

Local Stateでうまくやる方法 ②propを渡すこと自体はそんなに悪いことではない ● むしろ依存関係があるから、依存関係がわかるように書いている ● ただ個数が多かったり、バケツリレーを繰り返してたら疑うのは大切

Slide 21

Slide 21 text

Local Stateでうまくやる方法 ③そもそもそんなにComponentをネストさせる必要があるのか?

Slide 22

Slide 22 text

Local Stateでうまくやる方法 ③そもそもそんなにComponentをネストさせる必要があるのか? ※変更頻度が多く複数人で触るようなComponentが前提 ● ロジックやstateはCustom Hookで責任ごとに分ける ● 機能に依存しない小さな汎用Componentを作る ● 機能のComponentはそれらを組み合わせ機能内でのネストは最小限にする ○ Viewの全体像がわかりやすい ○ 不要なインターフェースが生まれず、柔軟性が保たれる

Slide 23

Slide 23 text

Local Stateでうまくやる方法 ④Composition: childrenを使う propが減って変更に強くなり、また状態の依存関係がわかりやすくなる

Slide 24

Slide 24 text

Local Stateでうまくやる方法 ⑤Composition: render props使う 親Componentの肥大化を防ぎたい時におすすめ(初見の難しさが少し上がる)

Slide 25

Slide 25 text

Local Stateでうまくやる方法 実装的にGlobal Stateで管理したくなるケース ● 子、孫Component間でstateを共有したい ● propsのバケツリレー(props drilling)を避けたい ● 子Component内のstateを親Componentから制御したい

Slide 26

Slide 26 text

Local Stateでうまくやる方法 ①やっぱりまずは基本のLifting State Up そもそも親から制御したいという要求の時点で危険な臭いがする… (ただ実際やりたいケースもあるので紹介していく)

Slide 27

Slide 27 text

Local Stateでうまくやる方法 ⑥Component自体を初期化する ● 親から制御したい多くのケースはstateの初期化 ● Componentに動的なkeyを渡すとkeyごとにComponentを作り直してくれる

Slide 28

Slide 28 text

Local Stateでうまくやる方法 ⑥Component自体を初期化する ● 親から制御したい多くのケースはstateの初期化 ● Componentに動的なkeyを渡すとkeyごとにComponentを作り直してくれる 「〇〇から◆◆に変わったら、△△する」のではなく、 「〇〇の時は♡♡、◆◆の時は△△する」と考えるのが大切(宣言的)

Slide 29

Slide 29 text

Local Stateでうまくやる方法 ⑥Component自体を初期化する ● 親から制御したい多くのケースはstateの初期化 ● Componentに動的なkeyを渡すとkeyごとにComponentを作り直してくれる →「いやいやComponentをUnmountさせるのはUX的にやりたくない」 →「特定のstateだけ初期化(制御)したい」

Slide 30

Slide 30 text

Local Stateでうまくやる方法 ⑦propとstateの値からsetStateする

Slide 31

Slide 31 text

Local Stateでうまくやる方法 ⑦propとstateの値からsetStateする ● 状態の性質として正しい姿を宣言する ● useEffectは不要( 使うと前のstateで一度DOMにcommitされてしまう) 「〇〇から◆◆に変わったら、△△する」のではなく、 「〇〇の時は♡♡、◆◆の時は△△する」と考えるのが大切(宣言的)

Slide 32

Slide 32 text

Local Stateでうまくやる方法 ⑧前レンダリング時のstateやpropの値を保持するstateを使う ● これは正直あんまりやりたくない ● ここまでくるともしかしたらGlobal Stateを使う方がシンプルかもしれない

Slide 33

Slide 33 text

Local Stateでうまくやる方法 ①まずは基本のLifting State Up ②propを渡すこと自体はそんなに悪いことではない ③そもそもそんなにComponentをネストさせる必要があるのか考える ④Composition: childrenを使う ⑤Composition: render propsを使う ⑥Component自体を初期化する ⑦propとstateの値からsetStateする ⑧前レンダリング時のstateやpropの値を保持するstateを使う

Slide 34

Slide 34 text

まとめ

Slide 35

Slide 35 text

まとめ ● 実装都合でGlobal Stateを使う時はむずかしさの考慮を忘れずに ○ 制約がない・自由の裏には何があるのか ● 設計を見直すとLocal Stateでも意外といける ○ Hackではなく全て公式ドキュメントの方法

Slide 36

Slide 36 text

積極採用中です!!
 採用情報はこちら! https://hello.shelfy.co.jp