Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Jotaiで作ったフォームをApollo_Clientで投げたらいい感じだった件.pdf
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
asazu taiga
March 21, 2023
Technology
1k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Jotaiで作ったフォームをApollo_Clientで投げたらいい感じだった件.pdf
asazu taiga
March 21, 2023
More Decks by asazu taiga
See All by asazu taiga
副業やってみた
asazutaiga
0
400
Hydrationから知るAstro, Qwik
asazutaiga
0
770
(LT)ApolloClientとGraphQL Code Generatorの話
asazutaiga
0
140
2021新春Reactが怖くなくなる話
asazutaiga
0
260
Other Decks in Technology
See All in Technology
Claude Designがめちゃくちゃ便利なので使ってほしい
diggymo
0
180
全社共通データ基盤をつくる。ソニーのDatabricks活用とデータガバナンス設計の裏側
sony
0
290
サーバーフルコンピューティング?AWS Lambda
iwatatomoya
0
110
AIは爆速なのに、私が詰まっていた話 ― 音声入力と鳴くマスコットでボトルネックを削る
yama3133
0
200
SQL Server 2025 最適化されたロック
odashinsuke
0
110
AgentCoreで実践するハーネスエンジニアリング
yakumo
0
140
spanner-autoscalerに学ぶ CRD設計パターン 〜自動化と緊急時対応を両立する Kubernetesコントローラーの作り方〜
tkuchiki
0
220
Mastering Agentic Development: Harness Engineering for Effective Coding Agents
konippi
3
670
【Findyテック文化祭ワークショップ】新卒エンジニア&採用担当と作る、 なりたい姿と今やるべき一歩
dip_tech
PRO
0
150
Claude起点の仕様駆動開発
tanakaseiya
0
260
行動するAIのためのオントロジー | DevRev — Encraft #26.pdf
dvrv_tknrszk
2
660
CI/CDではもう遅い - 人とAIが迂回しないDevSecOps Verify基盤の再設計 -
kintotechdev
1
580
Featured
See All Featured
BBQ
matthewcrist
89
10k
Product Roadmaps are Hard
iamctodd
55
13k
Unsuck your backbone
ammeep
672
58k
[Rails World 2026] Durable orchestration on Rails: from continuation to workflow
palkan
1
400
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.4k
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
1
610
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
440
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2.2k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6.1k
Building an army of robots
kneath
307
47k
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
560
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
960
Transcript
Jotaiで作ったフォームを Apollo Clientで投げたら いい感じだった件 Asazu Taiga @JADE K.K. 2023.3.21 Saitama.js@大宮 【React】
Saitama.js オフライン開催 おめでとうございます! あーしもよろこんでいます ※公式の利用ルールに則り、非営利目的にて春日部つむぎさん素材を利用させていただいております
タイトルに「いい感じ」とありますが、 本当にいい感じなのか?は 皆さんの目でお確かめください (登壇申し込み時点ではいい感じだと思ってた)
自己紹介 • Asazu Taiga • twitter ◦ @AsazuTaiga • 所属
◦ 株式会社JADE • 最近好きなもの ◦ VTuberの音楽 ◦ ボイロキッチン動画 ▪ (自炊しないのに)
Agenda
Agenda • Jotaiの紹介 • Apollo Clientの紹介 • GraphQL Code Generatorの紹介
• Jotaiを使ったフォームの作成 • デモ • ちょっといい感じポイント • ちょっとどうかなポイント • まとめ • 質疑応答
Jotaiの紹介
Jotaiとは? • グローバルな状態管理ライブラリ • Recoilに触発されたアトミックなアプローチ • アトムの組み合わせによる依存関係に基づく自動最適化 ◦ 再レンダリング問題の解決、メモ化が不要 •
シンプルなuseStateの置き換えから複雑な アプリケーションまで幅広く対応 ◦ ユーティリティも豊富にある
Jotai サンプル(公式から引用) import { atom, useAtom } from 'jotai' //
Create your atoms and derivatives const textAtom = atom('hello') const uppercaseAtom = atom( (get) => get(textAtom).toUpperCase() ) // Use them anywhere in your app const Input = () => { const [text, setText] = useAtom(textAtom) const handleChange = (e) => setText(e.target.value) return ( <input value={text} onChange={handleChange} /> ) }
Jotai サンプル(公式から引用) const Uppercase = () => { const [uppercase]
= useAtom(uppercaseAtom) return ( <div>Uppercase: {uppercase}</div> ) } // Now you have the components const App = () => { return ( <> <Input /> <Uppercase /> </> ) }
Apollo Clientの紹介
Apollo Clientとは? • JavaScript向けの包括的な状態管理ライブラリ ◦ GraphQLクライアント ◦ ローカルとリモートの両方のデータを管理 • データの取得、キャッシュ、変更を行い、
UIを自動的に更新 • GraphQL Code Generatorと組み合わせることで、 TypeScriptとの統合がより便利になる
Apollo Client サンプル(公式から引用) const GET_LOCATIONS = gql` query GetLocations {
locations { id name description photo } } `;
Apollo Client サンプル(公式から引用、一部略) function DisplayLocations() { const { loading, error,
data } = useQuery(GET_LOCATIONS); if (loading) return <p>Loading...</p>; if (error) return <p>Error : {error.message}</p>; return data.locations.map(({ id, name, description, photo }) => ( <div key={id}>(中略...)</div> )); }
GraphQL Code Generatorの紹介
GraphQL Code Generatorの雰囲気が伝わる図 .graphql ドキュメント .graphqls スキーマ @graphql-codegen/cli 各種プラグイン (TypeScriptの型定義生成、
Apolloのhooksのラッパー生成 etc…) generated.ts
Jotaiを使ったフォームの作成
None
None
None
Jotaiを使ったフォームの作成 ※jotai-formというatomWithValidate()を提供する utilライブラリもありますが、今回は使いません 理由 • Jotai本体だけで十分に柔軟な表現ができる(気がする) • validate()関数をアトムに追加できるだけなので 恩恵がさほど大きくない(気がする)
Jotaiを使ったフォームの作成 - nameフィールドの例 // エラーメッセージを表示するかどうかを判定するためのatom(フォーム全体で共有) const shouldShowErrorMessageAtom = atom(false); const
nameAtom = atom(""); const nameSchema = z .string() .min(3, "名前は3文字以上で入力してください") .max(20, "名前は20文字以内で入力してください");
Jotaiを使ったフォームの作成 - nameフィールドの例 const nameErrorAtom = atom((get) => { const
name = get(nameAtom); const result = nameSchema.safeParse(name); if (result.success) { return ""; } return result.error.issues[0].message; }); const nameDisplayErrorAtom = atom((get) => { const shouldShow = get(shouldShowErrorMessageAtom); const error = get(nameErrorAtom); return shouldShow ? error : ""; }); export const useName = () => { const [value, setValue] = useAtom(nameAtom); const errorMessage = useAtomValue(nameDisplayErrorAtom); return { value, setValue, errorMessage }; };
デモ
デモ Website https://asazutaiga.github.io/jotai-examples/dist/index. html Repository https://github.com/asazutaiga/jotai-examples
ちょっといい感じポイント
ちょっといい感じポイント • クロスフィールドバリデーションが書きやすい • Mutation引数等、型変換をかませた派生atomが便利 • 利用側のコードがシンプルになる • 状態依存部分を最小限に切り出したコンポーネントを書 けば再レンダリングは控えめ
クロスフィールドバリデーションが書きやすい const passwordErrorAtom = atom((get) => { const password =
get(passwordAtom); // example: cross field validation // 実際こんなことはしないと思うが、例として const name = get(nameAtom); if (name === password) { return "名前とパスワードは異なるものにしてください "; } return ""; });
Mutation引数等、型変換をかませた派生atomが便利 // mutationの引数:GraphQL Code Generatorで生成した型を使うことができる // この例では単にそのまま値を各フィールドに渡しているだけだが、ここで適切な変換をかませることもできる const createUserVariablesAtom =
atom<CreateUserMutationVariables>((get) => ({ input: { name: get(nameAtom), email: get(emailAtom), password: get(passwordAtom), }, })); export const useCreateUserVariables = () => useAtomValue(createUserVariablesAtom);
Mutation引数等、型変換をかませた派生atomが便利 // 使う側はこんなにシンプル! // (いっそこれらをまとめたhookを作ってしまうのもよいが、ややオーバーか?) const variables = useCreateUserVariables(); const
[createUser, { loading }] = useCreateUserMutation({ variables, });
利用側のコードがシンプルになる const NameInput = () => { const { value,
setValue, errorMessage } = useName(); return ( <FormControl error={!!errorMessage}> <TextField label="Name" value={value} onChange={(e) => setValue(e.target.value)} /> <FormHelperText>{errorMessage}</FormHelperText> </FormControl> ); }; const InputView = () => { return ( <Stack gap={2} component="form" onSubmit={(e) => e.preventDefault()}> <NameInput /> <EmailInput /> <PasswordInput /> <Stack direction="row" gap={2}> <ResetButton /> <NextButton /> </Stack> </Stack> ); };
状態依存部分を最小限に切り出したコンポーネントを 書けば再レンダリングは控えめ デモで見てもらったように、 フォーム全体の再レンダリングはリセット時や モード(入力or確認)の切り替え時にしかおきません
ちょっとどうかなポイント
ちょっとどうかなポイント • テンプレ的な記述を多く書くのが大変 • フィールドが増えた際に依存フィールドの修正もれそう • グローバルで命名の衝突を避けようとすると変数名が長 くなりがち
テンプレ的な記述を多く書くのが大変 すでに見てもらったように、一つのフィールドに対して • 値atom • 内部エラーatom • 表示用エラーatom の3つは最低でも定義したくなる フィールドが増えれば、それだけatomの管理も大変に...
フィールドが増えた際に依存フィールドの修正もれそう // フォームの入力値をリセットするためのatom const resetFormAtom = atom(null, (get, set) =>
{ set(nameAtom, ""); set(emailAtom, ""); set(passwordAtom, ""); set(shouldShowErrorMessageAtom, false); }); addressが増えたら ここに足す...
フィールドが増えた際に依存フィールドの修正もれそう // フォーム全体をまたいで、エラーがあるかかないかを判定するためのatom const hasErrorAtom = atom((get) => { const
nameError = get(nameErrorAtom); const emailError = get(emailErrorAtom); const passwordError = get(passwordErrorAtom); return nameError || emailError || passwordError; }); ここもやんけ...
グローバルで命名の衝突を避けようとするとatom名が長 くなりがち • フォームの種別+フィールド名(+小区分)+atom ◦ createUserNameAtom ◦ createUserNameErrorAtom ◦ createUserNameDisplayErrorAtom
まとめ
まとめ • 派生状態を作りやすいJotai(atomベースの状態管理)の 特徴が、フォームの状態管理と結構マッチしている? • Apolloのことを散々書きましたが、APIのInputの型が あればGraphQLでもRESTでも関係ないですね(今更) • フォームの状態管理はみんな苦しんでいると思うので、 ひとつのありうる選択肢として捉えるとよさそう
Special Thanks 春日部つむぎさん(かわいい) Chat GPT(スライド作成手伝ってくれた)
質疑応答